SQLite 這幾年來已經成了一種標準用法,無論是嵌入式或是 PC 上的軟體,很容易看的到 SQLite 的蹤跡了。
對 Android 系統架構我還沒那麼熟,粗略知道它有 SQLiteDatabase 和 SQLiteOpenHelper 兩個 class 可供 SQLite 操作使用。網路上翻到的資料,大概要先撰寫一隻 SQLiteOpenHelper,此角色是用來初始化資料庫,包含建 Table 、資料庫升級等對應動作。有些人習慣把資料庫的操作都寫在同一個 class (extends SQLiteOpenHelper)中,由於我經驗尚淺,我不曉得這樣的做法是不是正確的,因為觀看一些物件特性及機制似乎不太恰當。以下用簡易範例當作筆記。
新增 MyDBHelper 並繼承 android.database.sqlite.SQLiteOpenHelper,接著實作 void onCreate(SQLiteDatabase db) 和 void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) 後,就算完成 SQLiteOpenHelper 的工作了:
package com.example.study;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
public class MyDBHelper extends SQLiteOpenHelper {
        final private static int _DB_VERSION = 1;
         final private static String _DB_DATABASE_NAME = "MyDatabases.db";
         public MyDBHelper(Context context) {
                 super(context,_DB_DATABASE_NAME,null,_DB_VERSION);
         }
         public MyDBHelper(Context context, String name, CursorFactory factory, int version) {
                 super(context, name, factory, version);
                 // TODO Auto-generated constructor stub
         }
        @Override
         public void onCreate(SQLiteDatabase db) {
                 // TODO Auto-generated method stub
                 db.execSQL(
                         "CREATE TABLE MyTable (" +
                                 " _ID INTEGER PRIMARY KEY, " +
                                 " _DATA VARCHAR(50) NOT NULL, " +
                                 " _DATETIME DATETIME NULL " +
                         ")"
                 );
         }
        @Override
         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
                 // TODO Auto-generated method stub
                 db.execSQL("DROP TABLE IF EXISTS MyTable");
                onCreate(db);
         }
}
接著在 MyTestingActivity 中,就可以操作:
package com.example.study;
import android.app.Activity;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.util.Log;
public class SQLiteDBTestingActivity extends Activity {
         /** Called when the activity is first created. */
         @Override
         public void onCreate(Bundle savedInstanceState) {
                 super.onCreate(savedInstanceState);
                 setContentView(R.layout.main);
 
                 // Init
                 MyDBHelper mHelper = new MyDBHelper(this);
                 SQLiteDatabase mDB = null;
 
                 // Insert by raw SQL
                 mDB = mHelper.getWritableDatabase();
                 mDB.execSQL( "INSERT INTO MyTable (_DATA,_DATETIME) VALUES ('Hello World', datetime('now'))");
                 mDB.close();
 
                 // Insert by object method
                 mDB = mHelper.getWritableDatabase();
                 ContentValues values = new ContentValues();
                 values.put("_DATA","YoHO");
                 values.put("_DATETIME","2012-05-09 20:30:00");
                 mDB.insertOrThrow("MyTable",null,values);
                 mDB.close();
 
                 // Query by raw SQL
                 mDB = mHelper.getWritableDatabase(); // mDB = mHelper.getReadableDatabase();
                 Cursor cursor = mDB.rawQuery("SELECT _ID, _DATA, _DATETIME FROM MyTable", null);
                 cursor.moveToFirst();
                 while(!cursor.isAfterLast()) {
                         Log.e("SQLiteDBTestingActivity","_ID = "+cursor.getInt(0));
                         Log.e("SQLiteDBTestingActivity","_DATA = "+cursor.getString(1));
                         Log.e("SQLiteDBTestingActivity","_DATETIME = "+cursor.getString(2).substring(0, 16));
                         cursor.moveToNext();
                 }
                 startManagingCursor(cursor);
                 cursor.close();
                 mDB.close();
         }
}
執行結果:
從上述片段程式來看,可以看到一開始 SQLiteOpenHelper 初始化必須傳入一個 Context,並且執行資料庫操作是透過 getWritableDatabase() 或 getReadableDatabase() 而來的,且查詢時會透過 Cursor 甚至 Activity 的 startManagingCursor 等動作,結束時還需做一些 close 的資源回收,因此,個人覺得把這一系列的動作都包進 SQLiteOpenHelper 似乎不太恰當。目前經驗尚淺,或許需要多累積一些實作經驗才會明瞭吧!
此外,可以透過 DDMS 將模擬器內的 SQLiteDB 取出來 (/data/data/com.example.study/databases/MyDatabases.db),並且用 sqlite3 等相仿的 cmd 去操作:
$ sqlite3 MyDatabases.db
SQLite version 3.6.22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .table
MyTable android_metadata
sqlite> SELECT * FROM MyTable;
1|Hello World|2012-05-09 12:41:07
2|YoHO|2012-05-09 20:30:00
sqlite>
 
請在 onUpgrade() drop 之後加上 onCreate(db);
回覆刪除否則程式將會在下次執行時出現 exception, 因為 table 已經被 drop 了, 無法再 insert.
版主回覆:(11/22/2012 05:47:14 AM)
感謝提醒 :D