在 10 月 2 日時,我們幫「寶寶生活記錄 App」的選單 (Menu) 新增了「新增寶寶」、「寶寶列表」和「寄信給開發者」三個選項,我們已經完成了「寄信給開發者」這個選項的實作,今天來討論「新增寶寶」與「寶寶列表」的實作(由於一個家庭內可能有複數個寶寶,因此利用一個列表 (List) 顯示所有寶寶是需要的),筆者會使用資料庫來儲存寶寶的資料,因此今天的重點是 Android 上資料庫的存取。
Android 內使用的是 SQLIte 資料庫 [1],它是一個輕量級的關聯式資料庫系統,由於其輕量級的特性,很適合使用在行動裝置上,筆者假設讀者已經了解何謂關聯式資料庫系統,也熟悉簡單的 SQL 語法,若不太熟悉資料庫的讀者,可自行於網路上利用「關聯式資料庫」、「SQL」等關鍵字進行搜尋或參考筆者的書籍 [2]。
Android 提供了兩個方便的 Class,讓我們可以輕鬆地建立/使用資料庫,這兩個 Class 分別是 SQLiteOpenHelper 和 SQLiteDatabase,今天我們先來介紹 SQLiteOpenHelper [3]。
SQLiteOpenHelper 這個抽象類別主要是幫助我們建立資料庫和管理資料庫版本,繼承SQLiteOpenHelper 的類別有兩個抽象方法一定要實作:onCreate 與 onUpgrade。假設我們想建立一個名為 babylog.db 的資料庫,SQLiteOpenHelper 會去檢查該資料庫檔案是否存在 (SQLite 會把資料庫內的所有資料儲存成單一一個檔案),如果不存在就會呼叫 onCreate,因此我們通常會於onCreate內做資料庫的初始化,例如表格 (Tables) 的建立。如果 babylog.db已經存在,但是既有 babylog.db的版本小於程式設定的版本,那麼 onUpgrade 就會被呼叫,例如我們幫某個表格新增一「欄」,那麼就應該把相關程式寫在onUpgrade,並於建構子內將資料庫版本加 1,當 SQLiteOpenHelper 開啟 babylog.db 發現版本是舊的,會呼叫onUpgrade,也就能因此新增一「欄」。根據筆者的經驗,沒有處理好 onUpgrade,會造成使用者更新 App 後發生閃退的情況,因此要提醒讀者:只要您有修改資料庫表格的結構,請記得一定要在 onUpgrade 撰寫相關的程式碼,並不厭其煩地多做測試。
現在我們來看相關的程式碼,首先筆者先反白 lincyu.babylog 這個 package,按右鍵選 New -> Package,輸入 db,如此就會產生 lincyu.babylog.db 這個新的 package (這步驟純粹是筆者自己的習慣,您不一定要照著做,您可以把程式碼直接放在 lincyu.babylog ),接著反白新的 package,按右鍵選 New -> Java Class,輸入 DBOpenHelper,如此就產生一個新的 Class,將這個 Class 的內容修改成如下所示:
1 package lincyu.babylog.db;
2
3 import android.content.Context;
4 import android.database.sqlite.SQLiteDatabase;
5 import android.database.sqlite.SQLiteOpenHelper;
6
7 public class DBOpenHelper extends SQLiteOpenHelper {
8
9 Context context;
10
11 public DBOpenHelper(Context context) {
12 super(context, "babylog.db", null, 1);
13 this.context = context;
14 }
15
16 @Override
17 public void onCreate(SQLiteDatabase db) {
18 db.execSQL(BabyDB.CREATE_BABY_TABLE);
19 }
20
21 @Override
22 public void onUpgrade(SQLiteDatabase db,
23 int oldV, int newV) {
24 }
25 }
在第 7 行,我們讓 DBOpenHelper 繼承剛剛介紹的 SQLiteOpenHelper,首先先來說明 11 ~ 14 行的建構子,建構子的第 1 個參數是一個 Context 物件 (前幾天介紹過了),第 2 個參數是資料庫的名稱,由於 SQLite 會把一個資料庫儲存成單一一個檔案,資料庫名稱也會是檔案名稱 (檔案則是會儲存在 /data/data/<app’s package name>/databases/ 下,其中 <app’s package name> 在我們的範例中是 lincyu.babylog),第 3 個參數根據說明「to use for creating cursor objects, or null for the default [3]」我們填上 null 即可,第 4 個參數則是設定「目前的資料庫版本」,如果儲存在儲存空間上的檔案 (/data/data/lincyu.babylog/databases/babylog.db),其版本小於第 4 個參數的值,那麼 onUpgrade 就會被呼叫,反之若大於第 4 個參數的值,則 onDowngrade 會被呼叫。
實作 SQLiteOpenHelper 的類別要實作 onCreate 和 onUpgrade 這兩個抽象方法,前面已經說明過這兩個 Method 的呼叫時機,因此這裡只討論實作,首先討論 onCreate,程式在第 18 行,我們呼叫 SQLiteDatabase 物件的 execSQL 方法來建立一個表格 (建立一個新資料庫後的第一個動作通常就是建立一個表格),由於明天才會討論 SQLiteDatabase 這個類別,因此第 18 行的細節就留到明天再說明,現在只需要知道,它的作用是「建立一個表格 (Table)」。而 22 ~ 24 行的 onUpgrade 裡面則是完全空白,這是因為目前的版本就只有一個 (版本號碼 1),不會有呼叫到 onUpgrade 的時候,因此保持空白即可,但未來若您想新增一個「媽媽姓名」的欄,您可能會加入如下的程式碼:「db.execSQL("alter table " + BabyDB.BABY_TABLE + " add column " + BabyDB.MOTHERNAME + ";");」。
今天我們簡單說明了如何利用 SQLiteOpenHelper 幫我們建立/管理資料庫,明天會繼續介紹 SQLiteDatabase 這個類別,它可以幫助我們新增/刪除/更新/搜尋資料庫內的資料。
參考資料
[1] SQLite Home Page, http://www.sqlite.org/
[2] 林致宇, Android程式設計入門與應用(附範例光碟), 全華出版社, ISBN: 9789572194126, http://www.opentech.com.tw/search/bookinfo.asp?isbn=9789572194126&companyID=04383129
[3] SQLiteOpenHelper | Android Developers, http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html