2. 详细代码
SQLiteDataBase示例程序下载地址 :
-- GirHub - https://github.com/han1202012/SQLite_NewsList.git.
(1) MainActivity代码
package shuliang.han.database; import android.app.Activity; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; import android.os.Bundle; import android.view.View; import android.widget.EditText; import android.widget.ListView; import android.widget.SimpleCursorAdapter; public class MainActivity extends Activity { private SQLiteDatabase db; //数据库对象 private ListView listView; //列表 private EditText et_tittle; //输入的新闻标题 private EditText et_content; //输入的新闻内容 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //打开或者创建数据库, 这里是创建数据库 db = SQLiteDatabase.openOrCreateDatabase(this.getFilesDir().toString() + "/news.db", null); System.out.println(this.getFilesDir().toString() + "/news.db"); //初始化组件 listView = (ListView) findViewById(R.id.lv_news); et_tittle = (EditText) findViewById(R.id.et_news_tittle); et_content = (EditText) findViewById(R.id.et_news_content); } /* * 插入数据到数据库中的触发点击事件 * 如果数据库存在就能正常访问数据库, 如果不存在访问数据库的时候就会出现 SQLiteException 异常 * 正常访问 : 获取输入的新闻标题 和 新闻内容, 将标题 和 内容插入到数据库, 重新获取Cursor, 使用Cursor刷新ListView内容 * 异常访问 : 如果访问出现了SQLiteException异常, 说明数据库不存在, 这时就需要先创建数据库 */ public void insertNews(View view) { String tittle = et_tittle.getText().toString(); String content = et_content.getText().toString(); try{ insertData(db, tittle, content); Cursor cursor = db.rawQuery("select * from news_table", null); inflateListView(cursor); }catch(SQLiteException exception){ db.execSQL("create table news_table (" + "_id integer primary key autoincrement, " + "news_tittle varchar(50), " + "news_content varchar(5000))"); insertData(db, tittle, content); Cursor cursor = db.rawQuery("select * from news_table", null); inflateListView(cursor); } } /* * 向数据库中插入数据 * 参数介绍 : * -- 参数① : SQL语句, 在这个语句中使用 ? 作为占位符, 占位符中的内容在后面的字符串中按照顺序进行替换 * -- 参数② : 替换参数①中占位符中的内容 */ private void insertData(SQLiteDatabase db, String tittle, String content) { db.execSQL("insert into news_table values(null, ?, ?)", new String[]{tittle, content}); } /* * 刷新数据库列表显示 * 1. 关联SimpleCursorAdapter与数据库表, 获取数据库表中的最新数据 * 2. 将最新的SimpleCursorAdapter设置给ListView */ private void inflateListView(Cursor cursor) { SimpleCursorAdapter cursorAdapter = new SimpleCursorAdapter( getApplicationContext(), R.layout.item, cursor, new String[]{"news_tittle", "news_content"}, new int[]{R.id.tittle, R.id.content}); listView.setAdapter(cursorAdapter); } @Override protected void onDestroy() { super.onDestroy(); //在Activity销毁的时候, 如果没有 if(db != null && db.isOpen()) db.close(); } }
(2) XML布局文件
主布局文件 :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="新闻标题" /> <EditText android:id="@+id/et_news_tittle" android:layout_width="fill_parent" android:layout_height="wrap_content" android:singleLine="true" android:hint="点击此处输入新闻标题"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="新闻内容" /> <EditText android:id="@+id/et_news_content" android:layout_width="fill_parent" android:layout_height="wrap_content" android:lines="2" android:hint="点击此处输入新闻内容"/> <Button android:id="@+id/bt_add_news" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="insertNews" android:text="添加新闻" /> <ListView android:id="@+id/lv_news" android:layout_width="fill_parent" android:layout_height="fill_parent"/> </LinearLayout>
ListView条目布局文件 :
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/tittle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="15dp" android:textColor="#FFFF00"/> <TextView android:id="@+id/content" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textSize="10dp" android:textColor="#00FF00"/> </LinearLayout>
效果图 :
三. SQLiteOpenHelper类操作数据库
单独使用SQLiteDataBase操作数据库的弊端: 对数据库的表进行操作的时候, 我们不知道数据库中表是否存在, 首先要进行表操作, 在出现异常之后, 在异常捕获的try catch 代码块中创建表, 这样操作很繁琐;
SQLiteOpenHelper作用 : 该类用来管理数据库的创建 和版本更新, 通常使用其子类, 实现onCreate() 和 onUpgrade()方法;
1. 类中的方法介绍
(1) 读写打开数据库
以读写的方式打开数据库 :先以读写方式打开数据库, 如果磁盘满了, 就会打开失败,然后会尝试以只读的方式打开数据库;
public SQLiteDatabase getReadableDatabase ()
(2) 写方式打开数据库
以写的方式打开数据库 :先以读写方式打开数据库, 如果磁盘满了, 就会出错,不推荐使用这种方法, 使用 getReadableDatabase()方法即可;
public SQLiteDatabase getWritableDatabase ()
(3) 创建数据库
创建数据库 : 第一次创建数据库的时候回调该方法, 一般在该方法中 创建数据库表;
public abstract void onCreate (SQLiteDatabase db)
方法解析 :
-- 调用时机: 当使用getReadableDatabase()方法 获取数据库 实例 的时候, 如果数据库不存在, 就会调用这个方法;
-- 方法内容 : 重写该方法一般 将 创建数据库表的 execSQL()方法 和 初始化表数据的一些 insert()方法写在里面;
(4) 更新数据库
更新数据库 : 升级软件的时候更新数据库表结构, 在数据库版本发生变化的时候调用;
public abstract void onUpgrade (SQLiteDatabase db, int oldVersion, int newVersion)
方法解析 :
-- 调用时机 : 数据库版本发生变化的时候回调, newVersion是当前数据库版本号, oldVersion是旧的版本号;
-- 识别版本 : 创建SQLiteOpenHelper子类对象的时候,必须传入一个version参数, 该参数就是当前数据库版本, 只要这个版本高于之前的版本, 就会触发这个onUpgrade()方法;
(5) 关闭数据库
关闭打开的数据库 :
public synchronized void close ()
2. 示例程序要点解析
(1) 在onCreate()方法中创建表
创建数据库表 : 定义一个数据库SQL语句, 之后在onCreate()方法中 execSQL()执行该语句;
final String SQL_CREATE_TABLE = "create table news_table (" + "_id integer primary key autoincrement, " + "news_tittle varchar(50), " + "news_content varchar(5000))"; @Override public void onCreate(SQLiteDatabase db) { db.execSQL(SQL_CREATE_TABLE); }
(2) 插入数据
插入内容 : 打开数据库,如果存在直接插入内容, 如果不存在就创建表在插入内容;
helper.getReadableDatabase().execSQL("insert into news_table values(null, ?, ?)", new String[]{tittle, content});
(3) 查询数据库
查询数据 : 使用SQLiteOpenHelper子类对象打开数据库, 并且执行查询语句;
Cursor cursor = helper.getReadableDatabase().rawQuery("select * from news_table", null);
(4) 解析Cursor记录
将Cursor中的数据转为 ArrayList<Map<String, String>> 类型数据 :
-- 遍历条件 : Cursor的moveToNext()方法, 如果成功移到下一个记录, 就执行循环内容;
-- 获取表中数据 : Cursor的getString(1) 就是获取 这一样记录中的 第二列的数据, 第一列是 "_id" 主键;
private ArrayList<Map<String, String>> cursor2list(Cursor cursor) { ArrayList<Map<String, String>> list = new ArrayList<Map<String,String>>(); //遍历Cursor while(cursor.moveToNext()){ Map<String, String> map = new HashMap<String, String>(); map.put("tittle", cursor.getString(1)); map.put("content", cursor.getString(2)); list.add(map); } return list; }
(5) 开启一个Activity并传递数据
流程 :
-- ① 创建Bundle对象 : 该对象可以存放数据, 并可以放到Intent对象中, 传递给另外的组件;
-- ② Bundle存数据 : 使用putSerializable()方法, 可以存放对象, 将 ArrayList<Map<String, String>> 存入里面;
-- ③ 创建Intent对象 : 传入要跳转的Activity的Class对象;
-- ④ Bundle加入Intent对象 : 将存放好数据的Bundle对象加入到Intent对象中;
-- ⑤ 开启Activity : 使用startActivity(intent)方法跳转Activity;
Bundle bundle = new Bundle(); bundle.putSerializable("news", cursor2list(cursor)); Intent intent = new Intent(this, SearchResultActivity.class); intent.putExtras(bundle); startActivity(intent);
(6) 在Activity中获取Intent传递的数据
执行流程 :
-- 获取Intent对象: 调用 getIntent()方法, 可以获取Activity跳转到额Intent对象;
-- 获取Bundle对象 : Intent对象调用 getExtras()方法, 可以获取存放数据的Bundle对象;
-- 将数据从Bundle对象取出 : 调用getSerializable()方法, 并将返回值转换成 List<Map<String, String>> 类型;
//获取跳转到该Activity的intent对象
Intent intent = getIntent();
//获取Intent对象所携带的数据
Bundle bundle = intent.getExtras();
//从Bundle中取出List<Map<String,String>>数据
@SuppressWarnings("unchecked")
List<Map<String, String>> list = (List<Map<String, String>>)bundle.getSerializable("news");
(7) 适配器转化
将 List<Map<String, String>> 类型数据转为 SimpleAdapter类型适配器 :
参数介绍 :
-- 参数① context : 上下文对象;
-- 参数②List<Map<String, String>> : 数据源;
-- 参数③ id : ListView元素条目布局文件;
-- 参数④ string[] : 数据源中Map对象的键;
-- 参数⑤ int[]: 数据源中Map每个键对应的值 存放的组件 id;
SimpleAdapter adapter = new SimpleAdapter( getApplicationContext(), //上下文对象 list, //数据源 R.layout.item, //List显示布局 new String[]{"tittle", "content"}, //List中map的键值 new int[]{R.id.tittle, R.id.content}); //填充到的布局文件
3. 实例程序源码
(1) SQLiteOpenHelper源码
package shuliang.han.newssearch; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class NewsSearchDatabaseHelper extends SQLiteOpenHelper { final String SQL_CREATE_TABLE = "create table news_table (" + "_id integer primary key autoincrement, " + "news_tittle varchar(50), " + "news_content varchar(5000))"; /* * 构造方法 : * 参数介绍 : * 参数① : 上下文对象 * 参数② : 数据库名称 * 参数③ : 数据库版本号 */ public NewsSearchDatabaseHelper(Context context, String name, int version) { super(context, name, null, version); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(SQL_CREATE_TABLE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { System.out.println("call update"); } }
(2) MainActivity源码
package shuliang.han.newssearch; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import android.app.Activity; import android.content.Intent; import android.database.Cursor; import android.os.Bundle; import android.view.View; import android.widget.EditText; import android.widget.ListView; import android.widget.SimpleCursorAdapter; public class MainActivity extends Activity { private NewsSearchDatabaseHelper helper; //数据库帮助类 private EditText et_tittle; //输入新闻标题 private EditText et_content; //输入新闻内容 private ListView listView; //显示新闻列表 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); helper = new NewsSearchDatabaseHelper(getApplicationContext(), "news", 1); //初始化控件 et_tittle = (EditText) findViewById(R.id.et_news_tittle); et_content = (EditText) findViewById(R.id.et_news_content); listView = (ListView) findViewById(R.id.lv_news); } /* * 按钮点击事件 * 通过判断被点击的组件, 执行不同的操作 */ public void onClick(View view) { int id = view.getId(); switch (id) { case R.id.bt_add_news: insertNews(); break; case R.id.bt_query_news: queryNews(); break; default: break; } } /* * 插入新闻数据 * 1. 从EditText组件中获取新闻的标题 和 新闻内容 * 2. 获取数据库并从将 新闻标题 和 内容 插入到数据库中 * 3. 重新查询数据库 获得Cursor对象 * 4. 根据cursor对象创建SimpleCursorAdapter对象 * 5. 将SimpleCursorAdapter设置给ListView, 显示新闻列表 */ private void insertNews() { String tittle = et_tittle.getText().toString(); String content = et_content.getText().toString(); helper.getReadableDatabase().execSQL("insert into news_table values(null, ?, ?)", new String[]{tittle, content}); Cursor cursor = helper.getReadableDatabase().rawQuery("select * from news_table", null); inflateListView(cursor); } /* * 刷新数据库列表显示 * 1. 关联SimpleCursorAdapter与数据库表, 获取数据库表中的最新数据 * 2. 将最新的SimpleCursorAdapter设置给ListView */ private void inflateListView(Cursor cursor) { SimpleCursorAdapter cursorAdapter = new SimpleCursorAdapter( getApplicationContext(), R.layout.item, cursor, new String[]{"news_tittle", "news_content"}, new int[]{R.id.tittle, R.id.content}); listView.setAdapter(cursorAdapter); } /* * 查询新闻 * 1. 获取要查询的新闻标题 和 新闻内容 * 2. 查询数据库 获取 Cursor, 并将Cursor转化为List<Map<String, String>>类型的集合 * 3. 将集合放入bundle, Intent开启另一个Activity, 将bundle放入intent对象, 跳转Activity * */ private void queryNews() { String tittle = et_tittle.getText().toString(); String content = et_content.getText().toString(); Cursor cursor = helper.getReadableDatabase().rawQuery( "select * from news_table where news_tittle like ? or news_content like ?", new String[]{"%" + tittle + "%", "%" + content + "%"}); Bundle bundle = new Bundle(); bundle.putSerializable("news", cursor2list(cursor)); Intent intent = new Intent(this, SearchResultActivity.class); intent.putExtras(bundle); startActivity(intent); } /* * 返回一个ArrayList集合, 这个集合中每个元素是一个Map集合, 每个Map集合有两个元素 * 解析Cursor对象 : * 1. cursor光标向下移动一格; * 2. 创建一个HashMap对象 * 3. 使用 cursor.getString(列标号)获取该行中某列值, 将这个值放入map中 * 4. 将Map对象放入 */ private ArrayList<Map<String, String>> cursor2list(Cursor cursor) { ArrayList<Map<String, String>> list = new ArrayList<Map<String,String>>(); //遍历Cursor while(cursor.moveToNext()){ Map<String, String> map = new HashMap<String, String>(); map.put("tittle", cursor.getString(1)); map.put("content", cursor.getString(2)); list.add(map); } return list; } @Override protected void onDestroy() { super.onDestroy(); //释放数据库资源 if(helper !=null) helper.close(); } }
(3) SearchResultActivity源码
package shuliang.han.newssearch; import java.util.List; import java.util.Map; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.widget.ListView; import android.widget.SimpleAdapter; public class SearchResultActivity extends Activity { private ListView listView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //设置布局文件 setContentView(R.layout.news_search_result); //初始化组件 listView = (ListView) findViewById(R.id.lv_search_result); //获取跳转到该Activity的intent对象 Intent intent = getIntent(); //获取Intent对象所携带的数据 Bundle bundle = intent.getExtras(); //从Bundle中取出List<Map<String,String>>数据 @SuppressWarnings("unchecked") List<Map<String, String>> list = (List<Map<String, String>>)bundle.getSerializable("news"); SimpleAdapter adapter = new SimpleAdapter( getApplicationContext(), //上下文对象 list, //数据源 R.layout.item, //List显示布局 new String[]{"tittle", "content"}, //List中map的键值 new int[]{R.id.tittle, R.id.content}); //填充到的布局文件 listView.setAdapter(adapter); } }
(4) XML文件
主界面布局 :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="新闻标题" /> <EditText android:id="@+id/et_news_tittle" android:layout_width="fill_parent" android:layout_height="wrap_content" android:singleLine="true" android:hint="点击此处输入新闻标题"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="新闻内容" /> <EditText android:id="@+id/et_news_content" android:layout_width="fill_parent" android:layout_height="wrap_content" android:lines="2" android:hint="点击此处输入新闻内容"/> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_gravity="center_horizontal"> <Button android:id="@+id/bt_add_news" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="添加新闻" /> <Button android:id="@+id/bt_query_news" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="查找新闻" /> </LinearLayout> <ListView android:id="@+id/lv_news" android:layout_width="fill_parent" android:layout_height="fill_parent"/> </LinearLayout> ListView条目布局 : <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/tittle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="15dp" android:textColor="#FFFF00"/> <TextView android:id="@+id/content" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textSize="10dp" android:textColor="#00FF00"/> </LinearLayout> 跳转Activity布局 : <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <ListView android:id="@+id/lv_search_result" android:layout_height="wrap_content" android:layout_width="wrap_content"/> </LinearLayout>
SQLiteOpenHelper示例程序下载地址 :
-- GitHub : https://github.com/han1202012/NewsSearch.git .
效果图 :