橘子味的心
标题:7.4 Android SQLite数据库操作实例

上一节教程我们主要介绍了如何使用 Android SQLite 数据库存储数据,那么这一节我们就来实际操作一下吧!

实例 MyDbDemo 演示了使用 SQLiteOpenHelper 和 SQLiteDatabase 对数据库进行操作的过程,其运行效果如图 1 所示。

MyDbDemo界面
图 1  MyDbDemo界面

实例 MyDbDemo 使用 SQLiteOpenHelper 对象建立了数据库文件“mydb”,通过 SQLiteDatabase 对象对该数据库进行数据的查询、插入、修改和删除操作,并显示到 ListView 组件中。

实例 MyDbDemo 的运行界面实际上由两个 XML 文件组成,分别是 main.xml 和 listview.xml。其中 main.xml 文件的代码如下:
  1. <?xml version="1.0" encoding="utf-8"?>
  2.  
  3. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent"
  6. android:orientation="vertical">
  7.  
  8. <LinearLayout
  9. android:layout_width="fill_parent"
  10. android:layout_height="wrap_content"
  11. android:addStatesFromChildren="true">
  12.  
  13. <TextView
  14. android:layout_width="wrap_content"
  15. android:layout_height="wrap_content"
  16. android:text="姓名"
  17. android:textColor="?android:attr/textColorSecondary" />
  18.  
  19. <EditText
  20. android:id="@+id/et_name"
  21. android:layout_width="wrap_content"
  22. android:layout_height="wrap_content"
  23. android:layout_weight="1"
  24. android:singleLine="true" />
  25. </LinearLayout>
  26.  
  27. <LinearLayout
  28. android:layout_width="fill_parent"
  29. android:layout_height="wrap_content"
  30. android:addStatesFromChildren="true">
  31.  
  32. <TextView
  33. android:layout_width="wrap_content"
  34. android:layout_height="wrap_content"
  35. android:text="年龄"
  36. android:textColor="?android:attr/textColorSecondary" />
  37.  
  38. <EditText
  39. android:id="@+id/et_age"
  40. android:layout_width="wrap_content"
  41. android:layout_height="wrap_content"
  42. android:layout_weight="1"
  43. android:singleLine="true" />
  44. </LinearLayout>
  45.  
  46. <LinearLayout
  47. android:layout_width="fill_parent"
  48. android:layout_height="wrap_content"
  49. android:addStatesFromChildren="true"
  50. android:gravity="center">
  51.  
  52. <Button
  53. android:id="@+id/bt_add"
  54. android:layout_width="wrap_content"
  55. android:layout_height="wrap_content"
  56. android:onClick="addbutton"
  57. android:text="添加"></Button>
  58.  
  59. <Button
  60. android:id="@+id/bt_modify"
  61. android:layout_width="wrap_content"
  62. android:layout_height="wrap_content"
  63. android:onClick="updatebutton"
  64. android:text="修改"></Button>
  65.  
  66. <Button
  67. android:id="@+id/bt_del"
  68. android:layout_width="wrap_content"
  69. android:layout_height="wrap_content"
  70. android:onClick="updatebutton"
  71. android:text="删除"></Button>
  72.  
  73. <Button
  74. android:id="@+id/bt_query"
  75. android:layout_width="wrap_content"
  76. android:layout_height="wrap_content"
  77. android:onClick="querybutton"
  78. android:text="查询"></Button>
  79. </LinearLayout>
  80.  
  81. <ListView
  82. android:id="@+id/listView"
  83. android:layout_width="fill_parent"
  84. android:layout_height="wrap_content"
  85. android:padding="5dip"></ListView>
  86. </LinearLayout>
由代码可见,main.xml 实际上实现的是如图 2 所示的效果。

main.xml运行界面
图 2  main.xml 界面

该布局中放置了两个 TextView、两个 EditText 和 4 个按钮,在按钮的下面是一个 ListView 组件,但是该 ListView 没有对显示效果进行任何的限制。

实例 MyDbDemo 中 listview.xml 文件的代码如下:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3.     android:id="@+id/linear"
  4.     android:layout_width="wrap_content"
  5.     android:layout_height="wrap_content"
  6.     android:padding="5dip">
  7.  
  8.     <TextView
  9.         android:id="@+id/tvID"
  10.         android:layout_width="80dp"
  11.         android:layout_height="wrap_content" />
  12.  
  13.     <TextView
  14.         android:id="@+id/tvName"
  15.         android:layout_width="80dp"
  16.         android:layout_height="wrap_content" />
  17.  
  18.     <TextView
  19.         android:id="@+id/tvAge"
  20.         android:layout_width="80dp"
  21.         android:layout_height="wrap_content" />
  22. </LinearLayout>
可见 listview.xml 布局中横向放置了三个 TextView 用于显示数据。

该实例实际的运行效果是使用 listview.xml 中的数据格式替换 main.xml 中 ListView 组件的数据格式后实现的。该效果通过 LayoutInflater 类的对象进行实现。

实例 MyDbDemo 中 AndroidManifest.xml 文件的代码如下:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="introduction.android.mydbdemo"
  4. android:versionCode="1"
  5. android:versionName="1.0">
  6.  
  7. <uses-sdk android:minSdkVersion="14" />
  8. <application
  9. android:allowBackup="true"
  10. android:icon="@mipmap/ic_launcher"
  11. android:label="@string/app_name"
  12. android:roundIcon="@mipmap/ic_launcher_round"
  13. android:supportsRtl="true"
  14. android:theme="@style/AppTheme">
  15. <activity android:name=".MainActivity">
  16. <intent-filter>
  17. <action android:name="android.intent.action.MAIN" />
  18. <category android:name="android.intent.category.LAUNCHER" />
  19. </intent-filter>
  20. </activity>
  21. </application>
  22.  
  23. </manifest>
实例 MyDbDemo 中 SQLiteOpenHelper 的子类 dbHelper 的实现代码如下:
  1. package introduction.android.mydbdemo;
  2.  
  3. import android.content.Context;
  4. import android.database.sqlite.SQLiteDatabase;
  5. import android.database.sqlite.SQLiteDatabase.CursorFactory;
  6. import android.database.sqlite.SQLiteOpenHelper;
  7.  
  8. public class dbHelper extends SQLiteOpenHelper {
  9. public static final String TB_NAME = "friends";
  10.  
  11. public dbHelper(Context context, String name, CursorFactory factory, int version) {
  12. super(context, name, factory, version);
  13. // TODO Auto-generated constructor stub
  14. }
  15.  
  16. @Override
  17. public void onCreate(SQLiteDatabase db) {
  18. // TODO Auto-generated method stub
  19. db.execSQL("CREATE TABLE IF NOT EXISTS " +
  20. TB_NAME + " ( _id integer primary key autoincrement," +//
  21. "name varchar," +
  22. "age integer" +
  23. ") ");
  24. }
  25.  
  26. @Override
  27. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  28. // TODO Auto-generated method stub
  29. db.execSQL("DROP TABLE IF EXISTS " + TB_NAME);
  30. onCreate(db);
  31. }
  32. }
子类 dbHelper 重写了父类 SQLiteOpenHelper 的两个抽象方法 onCreate() 和 onUpgrade()。

在 onCreate() 方法中创建了一个名为 friends 的数据表,该数据表有 _id、name 和 age三个字段,其中 _id 为自增加主键。

onUpgrade() 方法实现了删除现有数据表并且重建的功能。

实例 MyDbDemo 中的主 Activity 所对应文件 MainActivity.java 的代码如下:
  1. package introduction.android.mydbdemo;
  2.  
  3.  
  4. import android.app.Activity;
  5. import android.content.ContentValues;
  6. import android.database.Cursor;
  7. import android.database.sqlite.SQLiteDatabase;
  8. import android.os.Bundle;
  9. import android.util.Log;
  10. import android.view.View;
  11. import android.widget.AdapterView;
  12. import android.widget.Button;
  13. import android.widget.EditText;
  14. import android.widget.ListView;
  15. import android.widget.SimpleAdapter;
  16.  
  17. import java.util.ArrayList;
  18. import java.util.HashMap;
  19. import java.util.Map;
  20.  
  21. public class MainActivity extends Activity {
  22. private static String DB_NAME = "mydb";
  23. private EditText et_name;
  24. private EditText et_age;
  25. private ArrayList<Map<String, Object>> data;
  26. private dbHelper dbHelper;
  27. private SQLiteDatabase db;
  28. private Cursor cursor;
  29. private SimpleAdapter listAdapter;
  30. private View view;
  31. private ListView listview;
  32. private Button selBtn, addBtn, updBtn, delBtn;
  33. private Map<String, Object> item;
  34. private String selId;
  35. private ContentValues selCV;
  36.  
  37. /**
  38. * Called when the activity is first created.
  39. */
  40. @Override
  41. public void onCreate(Bundle savedInstanceState) {
  42. super.onCreate(savedInstanceState);
  43. setContentView(R.layout.activity_main);
  44. et_name = (EditText) findViewById(R.id.et_name);
  45. et_age = (EditText) findViewById(R.id.et_age);
  46. listview = (ListView) findViewById(R.id.listView);
  47. selBtn = (Button) findViewById(R.id.bt_query);
  48. addBtn = (Button) findViewById(R.id.bt_add);
  49. updBtn = (Button) findViewById(R.id.bt_modify);
  50. delBtn = (Button) findViewById(R.id.bt_del);
  51. selBtn.setOnClickListener(new Button.OnClickListener() {
  52. @Override
  53. public void onClick(View v) {
  54. // TODO Auto-generated method stub
  55. dbFindAll();
  56. }
  57. });
  58.  
  59. addBtn.setOnClickListener(new Button.OnClickListener() {
  60. @Override
  61. public void onClick(View v) {
  62. // TODO Auto-generated method stub
  63. dbAdd();
  64. dbFindAll();
  65. }
  66. });
  67. updBtn.setOnClickListener(new Button.OnClickListener() {
  68. @Override
  69. public void onClick(View v) {
  70. // TODO Auto-generated method stub
  71. dbUpdate();
  72. dbFindAll();
  73. }
  74. });
  75. delBtn.setOnClickListener(new Button.OnClickListener() {
  76. @Override
  77. public void onClick(View v) {
  78. // TODO Auto-generated method stub
  79. dbDel();
  80. dbFindAll();
  81. }
  82. });
  83. dbHelper = new dbHelper(this, DB_NAME, null, 1);
  84. db = dbHelper.getWritableDatabase();// 打开数据库
  85. data = new ArrayList<Map<String, Object>>();
  86. dbFindAll();
  87. listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
  88. @Override
  89. public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
  90. // TODO Auto-generated method stub
  91. Map<String, Object> listItem = (Map<String, Object>) listview.getItemAtPosition(position);
  92. et_name.setText((String) listItem.get("name"));
  93. et_age.setText((String) listItem.get("age"));
  94. selId = (String) listItem.get("_id");
  95. Log.i("mydbDemo", "id=" + selId);
  96. }
  97. });
  98. }
  99.  
  100. //数据删除
  101. protected void dbDel() {
  102. // TODO Auto-generated method stub
  103. String where = "_id=" + selId;
  104. int i = db.delete(dbHelper.TB_NAME, where, null);
  105. if (i > 0)
  106. Log.i("myDbDemo", "数据删除成功!");
  107. else
  108. Log.i("myDbDemo", "数据未删除!");
  109. }
  110.  
  111. private void showList() {
  112. // TODO Auto-generated method stub
  113. listAdapter = new SimpleAdapter(this, data,
  114. R.layout.listview, new String[]{"_id", "name", "age"}, new int[]{R.id.tvID, R.id.tvName, R.id.tvAge});
  115. listview.setAdapter(listAdapter);
  116. }
  117.  
  118. //更新列表中的数据
  119. protected void dbUpdate() {
  120. // TODO Auto-generated method stub
  121. ContentValues values = new ContentValues();
  122. values.put("name", et_name.getText().toString().trim());
  123. values.put("age", et_age.getText().toString().trim());
  124. String where = "_id=" + selId;
  125. int i = db.update(dbHelper.TB_NAME, values, where, null);
  126. if (i > 0)
  127. Log.i("myDbDemo", "数据更新成功!");
  128. else
  129. Log.i("myDbDemo", "数据未更新");
  130.  
  131. }
  132.  
  133. //插入数据
  134. protected void dbAdd() {
  135. // TODO Auto-generated method stub
  136. ContentValues values = new ContentValues();
  137. values.put("name", et_name.getText().toString().trim());
  138. values.put("age", et_age.getText().toString().trim());
  139. long rowid = db.insert(dbHelper.TB_NAME, null, values);
  140. if (rowid == -1)
  141. Log.i("myDbDemo", "数据插入失败!");
  142. else
  143. Log.i("myDbDemo", "数据插入成功!" + rowid);
  144. }
  145.  
  146. //查询数据
  147. protected void dbFindAll() {
  148. // TODO Auto-generated method stub
  149. data.clear();
  150. cursor = db.query(dbHelper.TB_NAME, null, null, null, null, null, "_id ASC");
  151. cursor.moveToFirst();
  152. while (!cursor.isAfterLast()) {
  153. String id = cursor.getString(0);
  154. String name = cursor.getString(1);
  155. String age = cursor.getString(2);
  156. item = new HashMap<String, Object>();
  157. item.put("_id", id);
  158. item.put("name", name);
  159. item.put("age", age);
  160. data.add(item);
  161. cursor.moveToNext();
  162. }
  163. showList();
  164. }
  165. }
MainActivity 在 onCreate() 方法中调用 dbHelper 创建了数据库文件“mydb”,获取到该数据库的可写 SQLiteDatabase 对象,并将数据库中所有的数据显示到 listview 中。

MainActivity 为 main.xml 中的 4 个按钮分别添加按钮单击监视器并进行处理,通过 SQLiteDatabase 对象实现对数据库的 CRUD 操作。

其中:
  1. listAdapter = new SimpleAdapter(this, data,
  2. R.layout.listview,
  3. new String[]{"_id", "name", "age"},
  4. new int[]{R.id.tvID, R.id.tvName, R.id.tvAge});
  5. listview.setAdapter(listAdapter);
这几行代码通过 SimpleAdapter 将 listview.xml 文件中定义的 TextView 组件与 main.xml 中的 ListView 组件进行关联,这样就使 main.xml 中的 ListView 组件以 listview.xml 文件中定义的格式将数据显示出来。
  1. cursor = db.query(dbHelper.TB_NAME, null, null, null, null, null, "_id ASC");
  2. cursor.moveToFirst();
  3. while (!cursor.isAfterLast()) {
  4. String id = cursor.getString(0);
  5. String name = cursor.getString(1);
  6. String age = cursor.getString(2);
  7. item = new HashMap<String, Object>();
  8. item.put("_id", id);
  9. item.put("name", name);
  10. item.put("age", age);
  11. data.add(item);
  12. cursor.moveToNext();
  13. }
这几行代码从 friends 数据表中查询出所有数据,并按_id升序排列。

cursor.getString() 方法按照列将每条数据的对应字段分别取出来,通过 while 循环将所有数据保存到 data 中。
  1. listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
  2. @Override
  3. public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
  4. // TODO Auto-generated method stub
  5. Map<String, Object> listItem = (Map<String, Object>) listview.getItemAtPosition(position);
  6. et_name.setText((String) listItem.get("name"));
  7. et_age.setText((String) listItem.get("age"));
  8. selId = (String) listItem.get("_id");
  9. Log.i("mydbDemo", "id=" + selId);
  10. }
  11. });
这几行代码为 ListView 组件添加了单击监听器,并对单击事件进行了处理。

当用户单击 ListView 组件中的某条数据时,将该条数据的 name 和 age 字段显示到 main.xml 文件的 EditText 中,并将该记录的“_id”值存储到 selId 中,以便于对该条记录进行操作。

实例 MyDbDemo 中对数据库的 CRUD 操作分别通过 SQLiteDatabase 对象的 query、insert、update、delete 方法实现,此处不再描述。