[Android] 噗浪姬Project - Day2 SQLite Database
哈囉,又到了這個單元了,我想在進入主題前,先來介紹一下我擁有的環境吧
我的電腦是 Core 2 Quad E6600 第一代, RAM 6G ,手機是 HTC One X
所以我的程式在這樣的環境下大概會執行正常,其它環境要看我能不能借到手機作測試
如果程式執行不正常我也只能用現有的裝置來作測試(除非有借到)
今天就稍微介紹一下 SQLite Database 的使用吧,寫一隻 app 基本上不太可能不用到資料庫,而在 Android 上用的資料庫通常就是 SQLite ,這是個極為方便的輕型資料庫。
首先,我先實作一個類別 DBHelper ,該類別繼承 SQLiteOpenHelper
我的電腦是 Core 2 Quad E6600 第一代, RAM 6G ,手機是 HTC One X
所以我的程式在這樣的環境下大概會執行正常,其它環境要看我能不能借到手機作測試
如果程式執行不正常我也只能用現有的裝置來作測試(除非有借到)
今天就稍微介紹一下 SQLite Database 的使用吧,寫一隻 app 基本上不太可能不用到資料庫,而在 Android 上用的資料庫通常就是 SQLite ,這是個極為方便的輕型資料庫。
首先,我先實作一個類別 DBHelper ,該類別繼承 SQLiteOpenHelper
透過這個物件即可進行資料庫的存取
在 Day 1 時我有初步介紹過我有 Config, Friends 及 NameHistory 三張資料表
在這裡,我將依序實作他們相關的函式庫
我先定義了 IFactory 及 IRow 兩個 Interface ,其中 IFactory 定義了 TableName、Columns ,透過這個可以得到資料表的相關資料,而資料表的結構類別則繼承了 IRow
架構稍微介紹完了,那來介紹 adb 這個工具吧,為何要介紹?因為你看得到只是畫面,你完全不知你的資料是否有被成功寫進去了,而透過這個你完全可以一目瞭然,只是這個只支援 Shell 命令列,可能還是要稍微學一下(雖然 Google 也可以找到要用的指令並跟你說那指令的作用)。
我的噗浪姬的名稱為 wct.apps.plurk ,所以接下來將切到相對應的目錄
接下來開始介紹我程式碼的架構
IFactory.java
在這個介面我定義了需要有 TableName、Columns、CreateSQL、DropSQL、getAllData()、Create()及Drop()
TableName 為資料表的名字,Columns 為資料表的欄位, CreateSQL 建立資料表的語法,DropSQL 刪除資料表的語法,getAllData() 取得資料表的資料,Create()為建立資料表的呼叫函式,而 Drop() 則是刪除資料表的語法。
getToken、getTokenSecret及getDeviceID用來取得紀錄的 Config 資料,而 setToken、setTokenSecret及setDeviceID用來設定 Config 資料並存回資料庫。
最後來介紹 DBHelper,也就是存取資料庫最核心的部份
DBHelper 繼承 SQLiteOpenHelper 這個類別,並實作
onCreate 為建構資料庫時呼叫
onUpgrade 則是資料庫版本更新的話要如何處理
之後透過 DBHelper.getReadableDatabase 及 DBHelper.getWritableDatabase 取得讀取及寫入的 SQLiteDatabase,並透過這個類呼呼叫執行。
後記:
其實這篇的後記我是先打的,很高興你看到了這裡,Day2 單位也到此告一段落
如果有任何疑問或覺得哪邊可以改進的都可以與我討論
然後一直到現在我才想到要去註冊一個 API Key 來給這隻程式用
這時才驚覺從我之前註冊時才 34xx 到現在編號已經到 216xx 了,已經不知不覺多了這麼多 Apps 了
雖然 Facebook 應該會更多,但對 Facebook 我目前還是沒有什麼想法可以開發
大部份想得到的都已經有人作了,但之後有空拿 Facebook 來練練手也沒什麼不好的!
明天我想介紹的應該就是 OAuth 的使用了,再請多多指教。
Reference:
[Android] 使用adb指令
[Android] 建立SQLite資料庫
Android 手機資料庫(一) - SQLite 基本介紹、創建及查詢
架構稍微介紹完了,那來介紹 adb 這個工具吧,為何要介紹?因為你看得到只是畫面,你完全不知你的資料是否有被成功寫進去了,而透過這個你完全可以一目瞭然,只是這個只支援 Shell 命令列,可能還是要稍微學一下(雖然 Google 也可以找到要用的指令並跟你說那指令的作用)。
圖一、顯示目前的 Devices
如圖一所示,透過這個指令可以看到目前電腦連線的 android devices,而目前我只有一個 android 運作中。
圖二、進入 adb shell 畫面
輸入 adb shell 進入 shell 畫面,在這上面就類似 unix ,你可以輸入相關的指令進行系統的操控。
圖三、列出所有安裝的安裝列表
這裡可以看到該裝置上安裝的所有安裝,在這找到你的 apps我的噗浪姬的名稱為 wct.apps.plurk ,所以接下來將切到相對應的目錄
圖四、跳到 .db 檔的目錄
跳到該 apps 的資料庫目錄,輸入 ls 指令就可以看到儲存的資料庫。
圖五、透過 sqlite3 開啟資料庫
透過 sqlite3 指令 打開資料庫。
圖六、於 sqlite3 shell 上輸入 SQL 指令
輸入 .tables 可以查看目前所有的資料表, .schema 可以查看資料表的 Schema ,透過這樣的指令來查閱資料,可以用來確認SQL是否正確被執行。接下來開始介紹我程式碼的架構
IFactory.java
package wct.apps.plurk.Database.Tables; import java.util.ArrayList; public interface IFactory { String TableName = null; String[] Columns = null; String CreateSQL = null; String DropSQL = null; ArrayList<? extends IRow> getAllData(); void Create(); void Drop(); }
在這個介面我定義了需要有 TableName、Columns、CreateSQL、DropSQL、getAllData()、Create()及Drop()
TableName 為資料表的名字,Columns 為資料表的欄位, CreateSQL 建立資料表的語法,DropSQL 刪除資料表的語法,getAllData() 取得資料表的資料,Create()為建立資料表的呼叫函式,而 Drop() 則是刪除資料表的語法。
package wct.apps.plurk.Database.Tables; import java.util.ArrayList; import wct.apps.plurk.Database.DBHelper; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.util.Log; public final class ConfigFactory implements IFactory { // Private variable defined. private Context _context = null; private ArrayList這邊則是以 ConfigFactory 來舉例,裡面我定義了幾個簡單的資料表, Create 及 Drop 如前言所述可以用來建立資料表,insert 用來新增資料,而 update 則是更新資料。list = null; private String _Token = null; private String _TokenSecret = null; private String _DeviceID = null; private DBHelper _db = null; // Public variable defined. public static final String TableName = "Config"; public static final String CreateSQL = "CREATE TABLE IF NOT EXISTS " + TableName + " (" + "_id INTEGER PRIMARY KEY AUTOINCREMENT, " + "Name TEXT," + "Value TEXT" + ");"; public static final String DropSQL = "DROP TABLE IF EXISTS " + TableName + ";"; public final String[] Columns = new String[] {"_id", "Name", "Value"}; // Class Constructor public ConfigFactory(Context context) { this._context = context; this._db = new DBHelper(context, this); } public ConfigFactory(Context context, DBHelper db) { this._context = context; if(db == null) this._db = new DBHelper(context, this); else this._db = db; } // Class private function // Class public function public static ConfigFactory getInstance(Context context) { return new ConfigFactory(context); } public static ConfigFactory getInstance(Context context, DBHelper db) { return new ConfigFactory(context, db); } public void update(String name, String value) { SQLiteDatabase dbw = _db.getWritableDatabase(); ContentValues values = new ContentValues(); values.put("Value", value); long rtn = dbw.update(TableName, values, "Name=?", new String[]{name}); dbw.close(); } public void insert(String name, String value) { SQLiteDatabase dbw = _db.getWritableDatabase(); ContentValues values = new ContentValues(); values.put("Name", name); values.put("Value", value); long rtn = dbw.insert(TableName, null, values); dbw.close(); } public void ReloadDataFromDB() { DBHelper db = new DBHelper(_context); SQLiteDatabase dbr = db.getReadableDatabase(); Cursor cursor = dbr.query(TableName, Columns, null, null, null, null, null); if(list == null) list = new ArrayList (); else list.clear(); _Token = _TokenSecret = _DeviceID = null; while(cursor.moveToNext()) { Config c = new Config(); c._id = cursor.getInt(0); c.Name = cursor.getString(1); c.Value = cursor.getString(2); list.add(c); if(c.Name.equals("Token")) _Token = c.Value; else if(c.Name.equals("TokenSecret")) _TokenSecret = c.Value; else if(c.Name.equals("DeviceID")) _DeviceID = c.Value; } cursor.close(); dbr.close(); db.close(); } /** * Use this function to get consumer key. * @return string */ public String getToken() { if(list == null) ReloadDataFromDB(); return _Token; } /** * Use this function to get consumer secret. * @return */ public String getTokenSecret() { if(list == null) ReloadDataFromDB(); return _TokenSecret; } /** * Use this function to get Device ID. * @return */ public String getDeviceID() { if(list == null) ReloadDataFromDB(); return _DeviceID; } /** Use this function to set consumer key. * * @author WCT * @param value string */ public void setToken(String value) { if(list == null) ReloadDataFromDB(); if(_Token != null) { if(_Token.equals(value)) update("Token", value); } else insert("Token", value); } /** Use this function to set consumer secret. * * @author WCT * @param value string */ public void setTokenSecret(String value) { if(list == null) ReloadDataFromDB(); if(_TokenSecret != null) { if(_TokenSecret.equals(value)) update("TokenSecret", value); } else insert("TokenSecret", value); } /** Use this function to set Device ID. * * @author WCT * @param value string */ public void setDeviceID(String value) { if(list == null) ReloadDataFromDB(); if(_DeviceID != null) { if(_DeviceID.equals(value)) update("DeviceID", value); } else insert("DeviceID", value); } public ArrayList getAllData() { if(list == null) ReloadDataFromDB(); return list; } public void Create() { SQLiteDatabase dw = _db.getWritableDatabase(); dw.execSQL(CreateSQL); dw.close(); } public void Drop() { SQLiteDatabase dw = _db.getWritableDatabase(); dw.execSQL(DropSQL); dw.close(); } }
getToken、getTokenSecret及getDeviceID用來取得紀錄的 Config 資料,而 setToken、setTokenSecret及setDeviceID用來設定 Config 資料並存回資料庫。
最後來介紹 DBHelper,也就是存取資料庫最核心的部份
package wct.apps.plurk.Database; import android.content.Context; import android.database.DatabaseErrorHandler; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; public class DBHelper extends SQLiteOpenHelper { // Private variable defined. private final static int _DBVersion = 1; private final static String _DBName = "wctplurk.db"; private Context _context = null; private wct.apps.plurk.Database.Tables.ConfigFactory _ConfigFactory = null; private wct.apps.plurk.Database.Tables.FriendsFactory _FriendsFactory = null; private wct.apps.plurk.Database.Tables.NameHistoryFactory _NameHistoryFactory = null; // Public variable defined. // Class Constructor public DBHelper(Context context) { super(context, _DBName, null, _DBVersion); _context = context; } public DBHelper(Context context, wct.apps.plurk.Database.Tables.IFactory tableFactory) { super(context, _DBName, null, _DBVersion); _context = context; if(tableFactory != null && tableFactory instanceof wct.apps.plurk.Database.Tables.ConfigFactory) _ConfigFactory = (wct.apps.plurk.Database.Tables.ConfigFactory) tableFactory; else if(tableFactory != null && tableFactory instanceof wct.apps.plurk.Database.Tables.FriendsFactory) _FriendsFactory = (wct.apps.plurk.Database.Tables.FriendsFactory) tableFactory; else if(tableFactory != null && tableFactory instanceof wct.apps.plurk.Database.Tables.NameHistoryFactory) _NameHistoryFactory = (wct.apps.plurk.Database.Tables.NameHistoryFactory) tableFactory; } public DBHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); // TODO Auto-generated constructor stub _context = context; } public DBHelper(Context context, String name, CursorFactory factory, int version, DatabaseErrorHandler errorHandler) { super(context, name, factory, version, errorHandler); // TODO Auto-generated constructor stub _context = context; } // Class static function. public static DBHelper getInstance(Context context) { return new DBHelper(context); } // Class private function // Class public function @Override public void onCreate(SQLiteDatabase db) { // TODO Auto-generated method stub db.execSQL(wct.apps.plurk.Database.Tables.ConfigFactory.CreateSQL); db.execSQL(wct.apps.plurk.Database.Tables.FriendsFactory.CreateSQL); db.execSQL(wct.apps.plurk.Database.Tables.NameHistoryFactory.CreateSQL); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // TODO Auto-generated method stub db.execSQL(wct.apps.plurk.Database.Tables.ConfigFactory.DropSQL); db.execSQL(wct.apps.plurk.Database.Tables.FriendsFactory.DropSQL); db.execSQL(wct.apps.plurk.Database.Tables.NameHistoryFactory.DropSQL); } public wct.apps.plurk.Database.Tables.ConfigFactory getConfigFactory() { if(_ConfigFactory == null) _ConfigFactory = wct.apps.plurk.Database.Tables.ConfigFactory.getInstance(_context, this); return _ConfigFactory; } public wct.apps.plurk.Database.Tables.FriendsFactory getFriendsFactory() { if(_FriendsFactory == null) _FriendsFactory = wct.apps.plurk.Database.Tables.FriendsFactory.getInstance(_context, this); return _FriendsFactory; } public wct.apps.plurk.Database.Tables.NameHistoryFactory getNameHistoryFactory() { if(_NameHistoryFactory == null) _NameHistoryFactory = wct.apps.plurk.Database.Tables.NameHistoryFactory.getInstance(_context, this); return _NameHistoryFactory; } }
DBHelper 繼承 SQLiteOpenHelper 這個類別,並實作
onCreate 為建構資料庫時呼叫
onUpgrade 則是資料庫版本更新的話要如何處理
之後透過 DBHelper.getReadableDatabase 及 DBHelper.getWritableDatabase 取得讀取及寫入的 SQLiteDatabase,並透過這個類呼呼叫執行。
後記:
其實這篇的後記我是先打的,很高興你看到了這裡,Day2 單位也到此告一段落
如果有任何疑問或覺得哪邊可以改進的都可以與我討論
然後一直到現在我才想到要去註冊一個 API Key 來給這隻程式用
這時才驚覺從我之前註冊時才 34xx 到現在編號已經到 216xx 了,已經不知不覺多了這麼多 Apps 了
雖然 Facebook 應該會更多,但對 Facebook 我目前還是沒有什麼想法可以開發
大部份想得到的都已經有人作了,但之後有空拿 Facebook 來練練手也沒什麼不好的!
明天我想介紹的應該就是 OAuth 的使用了,再請多多指教。
Reference:
[Android] 使用adb指令
[Android] 建立SQLite資料庫
Android 手機資料庫(一) - SQLite 基本介紹、創建及查詢
留言
張貼留言