因為 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 的政策。