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