TShopping

 找回密碼
 註冊
搜索
查看: 281|回復: 0

[教學] Android數據存取之Databases

[複製鏈接]
發表於 2014-4-4 01:16:11 | 顯示全部樓層 |閱讀模式
 
Push to Facebook Push to Plurk Push to Twitter 
在Android平台上可以操作數據庫,這是第一次接觸Android時的驚豔之一。在Android平台上,綁定了SQLite數據庫,這個數據庫系統也是極具性格的,它的最大的應用場景是嵌入式系統,進一步瞭解可以參看這裡。
如果有JDBC的經驗,那麼在這裡會容易的多。Android中操作數據庫首先要通過一個 類:android.database.sqlite.SQLiteOpenHelper。它封裝了如何打開一個數據庫,其中當然也包含如果數據庫不存在 就創建這樣的邏輯。看一個例子:

pubilc class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "com.roiding.simple.note";
private static final int DATABASE_VERSION = 1;
private static final String NOTES_TABLE_NAME = "notes";
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + NOTES_TABLE_NAME
+ " (id integer primary key autoincrement, name text);");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS notes");
onCreate(db);
}
}
這裡面,如下的語句需要解釋:
super(context, DATABASE_NAME, null, DATABASE_VERSION)
數據庫連接的初始化,中間的那個null,是一個CursorFactory參數,沒有仔細研究這個參數,暫時置空吧。
public void onCreate(SQLiteDatabase db)
這裡面的onCreate是指數據庫onCreate時,而不是DatabaseHelper的onCreate。也就是說,如果已經指定 database已經存在,那麼在重新運行程序的時候,就不會執行這個方法了。要不然,豈不是每次重新啟動程序都要重新創建一次數據庫了!在這個方法中,完成了數據庫的創建工作。也就是那個execSQL()方法。
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
在程序的開發維護過程中,數據庫的結構可能會有變化,那麼這個方法就有用處了。在DatabaseHelper這個對象一創建時,就已經把參數 DATABASE_VERSION傳入,這樣,如果Android發現此版本與現有版本不一致,就會調用這個onUpgrate方法。於是,可以在這裡面實現一些數據的upgrade工作,比如說創建一個臨時表,將數據由臨時表中轉到新的表結構中。需要注意的是,這裡面的onUpgrade是在版本不一致時調用,也就是說不管當前需要的版本高於現有版本還是低於現有版本,都會出發這個方法,類似的這種情況,就需要對oldVersion和 newVersion進行判斷之後再決定使用什麼策略來更新數據。
在Android中,數據庫存放在 /data/data/PACKAGE_NAME/databases 目錄下。
接下來就可以使用這個Helper來操作數據庫了,操作數據庫也就無非是增、刪、改、查。先看一個增的例子:

public static void insert(Context context, String s) {
DatabaseHelper mOpenHelper = new DatabaseHelper(context);
String table = "notes";
String nullColumnHack = "id";
ContentValues values = new ContentValues();
values.put("name", "www.roiding.com");
long id = mOpenHelper.getReadableDatabase().insert(table,
nullColumnHack, values);
mOpenHelper.getReadableDatabase().close();
}
DatabaseHelper mOpenHelper = new DatabaseHelper(context);
如果和JDBC例子的話,這一步貌似就像是獲得了一個Statement,用它就可以操作數據庫了。
ContentValues values = new ContentValues();
Android在向數據庫中插入數據的時候,要求數據存放到ContentValues中,這裡面的ContentValues其實就是一個 Map,Key值是字段名稱,Value值是字段的值。這樣,也許你會發現一個問題,那數據類型怎麼辦?其實在SQLite數據庫中就是沒有數據類型的, 一切都是字符串。
mOpenHelper.getReadableDatabase().insert(table,nullColumnHack, values);
將數據入庫,注意這裡面有一個nullColumnHack,看文檔是和所有字段都是空的記錄有關係,我沒有去實驗他具體的效果,只是隨便給他一個字段名稱。
再看一個查的例子:

public static void select(Context context) {
DatabaseHelper mOpenHelper = new DatabaseHelper(context);
String table = "notes";
String[] columns = new String[] { "id", "name" };
String selection = "id>? and name<>?";
String[] selectionArgs = new String[] { "0", "roiding.com" };
String groupBy = null;
String having = null;
String orderBy = "id desc";
String limit = "1";
Cursor c = mOpenHelper.getReadableDatabase().query(table,
columns, selection, selectionArgs, groupBy, having, orderBy, limit);
c.moveToFirst();
for (int i = 0; i < c.getCount(); i++) {
String s = c.getString(1);
c.moveToNext();
}
c.close();
mOpenHelper.getReadableDatabase().close();
}
DatabaseHelper mOpenHelper = new DatabaseHelper(context);
於前文中的相同
mOpenHelper.getReadableDatabase().query();
通過mOpenHelper.getReadableDatabase(),會得到一個SQLiteDatabase類型的只讀的數據庫連接,在這裡直接調用了他的query方法。這個query方法相對複雜,因為他將一個完整的SQL語句拆成了若幹個部分:
table:表名。相當於SQL的from後面的部分。那如果是多表聯合查詢怎麼辦?那就用逗號將兩個表名分開,拼成一個字符串作為table的值。
columns:要查詢出來的列名。相當於SQL的select後面的部分。
selection:查詢條件,相當於SQL的where後面的部分,在這個語句中允許使用「?」,也就是說這個用法和JDBC中的 PreparedStatement的用法相似。
selectionArgs:對應於selection的值,selection有幾個問號,這裡就得用幾個值。兩者必須一致,否則就會有異常。
groupBy:相當於SQL的group by後面的部分
having:相當於SQL的having後面的部分
orderBy:相當於SQL的order by後面的部分,如果是倒序,或者是聯合排序,可以寫成類似這樣:String orderBy = 「id desc, name」;
limit:指定結果集的大小,它和Mysql的limit用法不太一樣,mysql可以指定從多少行開始之後取多少條,例如「limit 100,10」,但是這裡只支持一個數值。
c.moveToFirst();
這一句也比較重要,如果讀取數據之前,沒有這一句,會有異常。
c.getString(1);
與JDBC一致了,Android不支持按字段名來取值,只能用序號。
再看一個刪除和修改的例子:

public static void delete(Context context) {
DatabaseHelper mOpenHelper = new DatabaseHelper(context);
String table = "notes";
String selection = "id>? and name<>?";
String[] selectionArgs = new String[] { "0", "roiding.com" };
String whereClause = selection;
String[] whereArgs = selectionArgs;
mOpenHelper.getWritableDatabase().delete(table, whereClause, whereArgs);
mOpenHelper.getWritableDatabase().close();
}
有了上面的基礎這裡就容易理解了,這裡的whereClause相當於前面的selection,whereArgs相當於前面的 selectionArgs。

public static void update(Context context) {
DatabaseHelper mOpenHelper = new DatabaseHelper(context);
String table = "notes";
String selection = "id>? and name<>?";
String[] selectionArgs = new String[] { "0", "roiding.com" };
String whereClause = selection;
String[] whereArgs = selectionArgs;
ContentValues values = new ContentValues();
values.put("name", "www.roiding.com");
mOpenHelper.getWritableDatabase().update(table, values,
whereClause, whereArgs);
mOpenHelper.getWritableDatabase().close();
}
這個update的用法,綜合select和delete就可以理解。
注意:
Cursor和Databases要及時關閉,不然也會有異常。
getWritableDatabase()和getReadableDatabase()在當前的Android版本中貌似可以通用,像上面的 insert,用的就是getReadableDatabase。
在真實的應用中,會對上面這些基本操作做更高一級的抽象和封裝,使之更容易使用。在select時,除了用上述的方法,將分段的SQL語句傳進去之外,Android還支持一種方法:使用SQLiteQueryBuilder。如果使用的是上述的分段SQL語句的方法,在Android的內部實現中,也是先將分段的SQL使用SQLiteQueryBuilder的靜態方法來生成一個真正的SQL的,而且,我沒有看出來使用 SQLiteQueryBuilder的優勢


http://charles-android.blogspot.tw/2010/03/androiddatabases.html

 

臉書網友討論
您需要登錄後才可以回帖 登錄 | 註冊 |

本版積分規則



Archiver|手機版|小黑屋|免責聲明|TShopping

GMT+8, 2016-12-7 13:50 , Processed in 0.054834 second(s), 22 queries .

本論壇言論純屬發表者個人意見,與 TShopping綜合論壇 立場無關 如有意見侵犯了您的權益 請寫信聯絡我們。

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回復 返回頂部 返回列表