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