因為 app 要儲存資料在 SQLite 之前,必須先建立 app 用的資料庫檔案,故 Android 提供了 SQLiteOpenHelper 這個類別幫您管理您 app 的資料庫檔案。
首先,建立自己的 app 的 SQLiteOpenHelper:
public class DictionaryOpenHelper extends SQLiteOpenHelper
{
// 若您變更了資料庫的 schema, 就必須增加 DATABASE_VERSION 的值.
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = "whalintest.db";
SQLite(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db)
{
db.execSQL("CREATE TABLE table1 (field1 VARCHAR(5), field2 VARCHAR(9));");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
// This database is only a cache for online data, so its upgrade policy is
// to simply to discard the data and start over
db.execSQL("DROP TABLE IF EXISTS table1");
onCreate(db);
}
@Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
onUpgrade(db, oldVersion, newVersion);
}
}
在這類別中,我們 Override 了 3 個 method -- onCreate 和 onUpgrade、和 onDowngrade,onCreate 就是建立您的 app 要使用的資料庫;而當您的 app 增加了新的功能導致資料庫結構也要跟著調整時,要調整的程式碼就寫在 onUpgrade,並且 DATABASE_VERSION 這個變數的值,要比前一版的數字大,Android 在偵測到版本變大時,就會進行資料庫版本升級的動作,在本例是相當偷懶的 -- 直接砍掉重練!! :-P
相對地,Android 偵測到 DATABASE_VERSION 數字較原有的值小時,就會執行 onDowngrade。
然後在程式中進行資料的存取:
@SuppressLint("NewApi")
public class MainActivity extends Activity
{
Button button1;
public static final boolean DEVELOPER_MODE = BuildConfig.DEBUG;
@Override
protected void onCreate(Bundle savedInstanceState)
{
if(DEVELOPER_MODE)
{
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads()
.detectDiskWrites()
.detectNetwork() // or .detectAll() for all detectable problems
.penaltyLog()
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects()
.penaltyLog()
.penaltyDeath()
.build());
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button1 = (Button) findViewById(R.id.button1);
}
public void onButton1Click(View v)
{
Thread thread = new Thread()
{
@Override
public void run()
{
super.run();
SQLite mDbHelper = new SQLite(getBaseContext());
// 以寫入模式開啟資料庫
SQLiteDatabase db = mDbHelper.getWritableDatabase();
// 將要存入的欄位-值 以 ContentValues 做準備
ContentValues values = new ContentValues();
values.put("field1", "ann");
values.put("field2", "huang");
// 以 insert 存入一筆記錄
long newRowId;
newRowId = db.insert("table1", null, values);
// 記得使用完畢後要關閉
db.close();
mDbHelper.close();
// --------------------
mDbHelper = new SQLite(getBaseContext());
// 以讀取模式開啟資料庫
db = mDbHelper.getReadableDatabase();
// db.query(table, columns, selection, selectionArgs, groupBy, having, orderBy);
// 不用到的功能或選項就填入 null
Cursor rs = db.query("table1", null, "field1=\"ann\" ", null, null, null, null);
// 或是您也可以用 rawQuery, 輸入完整的 SQL 語法
// 這在查詢 2 個以上的資料表時很好用
// db.rawQuery("SELECT a.field1, b.field3, b.field4 FROM table1 a, table2 b \n" +
// " WHERE a.field1=b.field2" , null);
// 記得使用完畢後要關閉
rs.close();
db.close();
mDbHelper.close();
}
};
thread.start();
}
}
db.query() 中 columns 若為 null 則表全部的欄位,等於一般的 SELECT * FROM,selection 和 selectionArgs 就是 SQL 指令中的 WHERE 述句,selection 是欄位,selectionArgs 是要符合的條件,偷懶的寫法是 -- 直接在 selection 填入全部的 WHERE 條件,selectionArgs 則為 null。
另外,還要注意每當下了 db.query() 指令後,就等於開啟了一個查詢結果資料集(query data set) ,要記得將它關閉。如下:
// 這裡開啟了一個 query data set
// 我們以 Cursor rs 去 reference 指向這個 data set
Cursor rs = db.query("table1", null, "field1=\"ann\" ", null, null, null, null);
rs.close();
// 重新 query,又開啟了一個 query data set
// 再將 rs 指向這個 data set
rs = db.query("table1", null, "field1=\"bryan\" ", null, null, null, null);
// 注意這裡我沒有執行 rs.close();
// 第三次 query,又開啟了一個 query data set
// 再將 rs 指向這個 data set
rs = db.query("table1", null, "field1=\"john\" ", null, null, null, null);
rs.close();
// 因為第二次的 query 沒有 close(),所以它一直處在開啟的狀態
// 而我們又將 rs 指向了第三次的 query data set
// 如果您有啟動 StrictMode 抓 bug,就會被 StrictMode 偵測到沒有關閉 query 的警告了
要連線資料庫查看資料的儲存狀況:
1. 先開啟一個 Android 模擬器,您會看到模擬器視窗左上角有個數字,我的是 5554
2. 開啟一個 "命令提示字元"視窗(DOS視窗) 以 cd 指令切換到您安裝的 sdk 資料夾的 platform-tools 下,舉例來說,我的 SDK 安裝在 D:\,則為
cd \ android\android-sdk\platform-tools
3. 下達連線模擬器指令
adb -s emulator-5554 shell
4. 連線您應用程式所使用資料庫,則下指令
sqlite3 /data/data/您的 package name/databases/資料庫名稱
這時您會看到多列文字顯示連線的過程
同時它也提示您, 下指令 .help 可取得輔助說明,並且下達的 SQL 指令要以 分號 做結尾
試著下 .dump,倒出資料庫所有資料
沒錯,我的確先前試寫時,執行了 db.insert(),在 table1 這個資料表存了三筆一樣的記錄。
退出 sqlite3 指令為 .exit,或按 CTRL+D
要記得舉凡 "磁碟機(含記憶卡)" 的存取,網線連線...不論管您在執行這些動作的程式碼多簡單,這些 Android 都認為是屬於耗時的工作,為有良好品質的 app,請將資料庫的存取視為耗時工作,將這段指令以 Thread 執行,並請用 StrictMode 來檢驗您的 app 指令有哪些是違反 StrictMode 的政策。

