SQLiteOpenHelper

Android提供操作SQLite的能力,但實際操作的是一個SQLiteDataBase物件,而SQLiteOpenHelper類別的任務是負責管理資料庫檔案的建立與版本控制。

SQLiteOpenHelper(context, database name, factory, database version)

SQLiteOpenHelper負責建立一個Helper物件來建立、開啟與管理一個SQLiteDatabase。在實作Helper類別時,name通常使用的是一個資料庫檔案(StudentList.db),也是一個組合過的路徑(/data/data/SQLite/StudentList.db)

onCreate(SQLiteDatabase db)

資料庫建立時所啟動執行的方法,代表會重新建立一個新的資料庫,通常在此階段把資料庫基本的SchemaTable或相關設定一併處理完畢。此方法在執行時,如遇到DB已存在,則進入onOpen()方法;如不存在則會先建立一個DataBase

onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)

此方法發生在當資料庫版本不一致時就會觸發。主要任務為因為在知道資料庫版本不同時,要進行資料的覆蓋或重建都必需要好好考量,因為有可能讓資料遺失或不一致。

onOpen(SQLiteDatabase db)

當資料庫被開啟時則進入此Method,配合SQLiteOpenHelper提供的二個方法相呼應:getReadableDatabase()getWritableDatabase()分別取得唯讀(Read-only)與可編輯(Write)的資料庫實體。然而,這二個方法即時觸發onCreateonUpgradeonOpen的來源者,所以上述介紹的幾個重要的方法,則真正被呼叫時是在getWritableDatabase()或是getReadableDatabase()被使用時。

SQLiteDataBase

Android程式實際操作的真正實體(database),提供所有操作SQLite的功能,包括:新增、修改、刪除、查詢等,協助操作裡面的資料,SQLiteDataBase提供一些已經包裝好的方法,當然也包括了指定SQL指令來操作資料的內容,除此之外,也支援Transcation的使用。beginTransaction()setTransactionSuccessful()endTransaction() 

execSQL(String sql)

專門執行單一非SelectSQL指令或是其他操作資料庫的指令,例如:建立資料表的指令、或是操作權限等相關的管理類的指令。

rawQuery(String sql, String[] selectionArgs)

如果今天針對要操作的資料,不單單只有一個Table而已時,即可以透過這個方法就像過去操作.NETSQLCommand物件方式,把SQL指令先撰寫好,交由SQLiteDatabase來操作資料。回傳值為:Cursor(其中也可以使用SQLiteCursor,它是Cursor的實作類別)

query/insert(String table, String nullColumnHack, ContentValues values)/update/delete

這是包裝好針對一個Table進行基本的新增、修改、刪除與查詢的固定方法,其使方法非常容易,透過指定的Table與相關的參數,包括:select的欄位、where的參數(使用[?] 做為參數取代值)Sort等,讓開發人員可以快速取得資料,但如果需要比較複雜的查詢,就建議使用上述的rawQuery()來執行。它一樣回傳一個Cursor物件。至於新增、修改與刪除的部分呢,將配合下方的物件來使用。

ContentValues/Cursor

在新增、修改、刪除的方法使用時,如果是使用上述已包裝好的方法,例如:insert(String table, String nullColumnHack, ContentValues values),則一定要了解ContentValuesContenResolver的使用方法。並且,這三個方法的使用,都會回傳成功影響的比數,如失敗則為:-1

ContentValues

專門用於欲操作的資料內容。透過put的方式操作內容值,這與過去直接操作data tabledata row是比較不同的。不過它相似於key/value的操作方式,因此,當在使用put(String key, object value)時,key則需要對應到tablecolumn name才行。

Cursor

則是操作查詢出來的結果,提供了相當豐富的方法與屬性,協助開發人員擷取資料的內容與移動索引值。

SQLiteCursor

它是實作Cursor的一個類別,主要承接從SQLiteDatabase查詢出來的資料,它被擷取出來之後,則與資料庫內的資料採不同步的方式,這也就是說,當query出來的結果被放入SQLiteCursor之後,它就像是一個Cache,後來如果其他程式段改了DB中的資料,則SQLiteCursor並不會被更新,需要重新查詢(requery())才有辦法取得。然而,SQLiteCursor類別提供很多便利的方法,包括:getCount()取得欄位數、getDatabase()取得來源資料庫等方法,操作起來如同使用.NET中的TableRowTableColumn的使用概念。

SQLiteStatement

該類別提供一個事先編譯(pre-compiled)SQL指令,讓該SQL指令可以重覆針對SQLiteDatabase使用時,不需要每次都重新編譯,常見的例子:連續性新增資料。但要特別注意的:"它無法回傳多筆資料(rows),只能11的資料集合被回傳"。另外,在使用它時,不需要new,只需直接使用compileStatement(String)語法即可。它也是非同步的物件,要同步都需要自己實作。

SQLiteQueryBuilder

如果透過String.format來組合SQL指令覺得不方便的話,可以使用SQLiteQueryBuiler類別來進行查詢指定的建立。它提供透過設定屬性與方法的方式,組合要查詢的相關SQL指令(buildQuery)。也有提供豐富的, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String)" target=_blank>, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String)" target=_blank>, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String)" target=_blank>buildUnionSubQuery等方法

 

在 Android 你可以透過 SQLite 來進行資料庫的存取。但是在使用前必需先自己實作 SQLiteOpenHelper 類別。在建立一個新的空白的class之後,加入「extends SQLiteOpenHelper」指令,系統就會要求建立基本的方法,依照系統指示所建立的程式框架如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package moke.test;
 
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
 
public class SQLite extends SQLiteOpenHelper {
	public SQLite(Context context, String name, CursorFactory factory,
			int version) {
		super(context, name, factory, version);
		// TODO Auto-generated constructor stub
		//context=內容物件;name=傳入資料庫名稱;factory=複雜查詢時使用;version=資料庫版本
	}
 
	@Override
	public void onCreate(SQLiteDatabase db) {
		// TODO Auto-generated method stub
 
	}
 
	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		// TODO Auto-generated method stub
 
	}
 
}

由於通常一支程式只會使用一個資料庫,因此我們可以省略建構子傳入的部份參數。此外,為了讓所有的方法都存取相同的資料庫,必需加入 SQLiteDatabase 物件。修改後的建構子如下:

8
9
10
11
12
13
14
15
16
	private static final String DATABASE_NAME = "moke_config.db";	//資料庫名稱
	private static final int DATABASE_VERSION = 1;	//資料庫版本
 
	private SQLiteDatabase db;
 
	public SQLite(Context context) {	//建構子
		super(context, DATABASE_NAME, null, DATABASE_VERSION);
		db = this.getWritableDatabase();
	}

接下來要實作 onCreate 與 onUpgrade 方法。onCreate 是當資料庫建立時會執行的方法,我們可以在這裡建立資料表或設定預設的資料庫參數。onUpgrade 是當資料庫的版本不一致時,會執行的方法。如果新舊版本的資料表格式不同,有二種處理方式。第一種是將舊的資料表刪除,直接建立新的資料表,但是這樣原有的資料就會消失,因此第二種方法是將舊的資料表按照新的表格格式儲存,存完之後再刪除舊的。這裡的範例先用最簡單的方式來撰寫,直接刪除舊的資料表。完整的 SQLiteOpenHelper 實作程式碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package moke.test;
 
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
 
public class SQLite extends SQLiteOpenHelper {
	private static final String DATABASE_NAME = "moke_config.db";	//資料庫名稱
	private static final int DATABASE_VERSION = 1;	//資料庫版本
 
	private SQLiteDatabase db;
 
	public SQLite(Context context) {	//建構子
		super(context, DATABASE_NAME, null, DATABASE_VERSION);
		db = this.getWritableDatabase();
	}
 
	@Override
	public void onCreate(SQLiteDatabase db) {
		String DATABASE_CREATE_TABLE =
		    "create table config ("
		        + "_ID INTEGER PRIMARY KEY,"
		        + "name TEXT,"
		        + "value INTEGER"
		    + ");";
		//建立config資料表,詳情請參考SQL語法
		db.execSQL(DATABASE_CREATE_TABLE);
	}
 
	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		//oldVersion=舊的資料庫版本;newVersion=新的資料庫版本
		db.execSQL("DROP TABLE IF EXISTS config");	//刪除舊有的資料表
		onCreate(db);
	}
}

「private SQLiteDatabase db;」物件變數,透過這個 db 變數可以對資料庫進行增刪改查的操作。

查詢
進行資料庫查詢時,必需建立一個方法回傳 Cursor 物件。查詢的方式有兩種。

1
2
3
4
	// 取得所有記錄
	public Cursor getAll() {
	    return db.rawQuery("SELECT * FROM table_name", null);
	}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
	// 取得所有記錄
	public Cursor getAll() {
		return db.query("table_name",		//資料表名稱
		new String[] {"_ID", "name", "value"},	//欄位名稱
		null, // WHERE
		null, // WHERE 的參數
		null, // GROUP BY
		null, // HAVING
		null  // ORDOR BY
		);
	}
	// 取得一筆紀錄
	public Cursor get(long rowId) throws SQLException {
		Cursor cursor = db.query(true,
		"table_name",				//資料表名稱
		new String[] {"_ID", "name", "value"},	//欄位名稱
		"_ID=" + rowId,				//WHERE
		null, // WHERE 的參數
		null, // GROUP BY
		null, // HAVING
		null, // ORDOR BY
		null  // 限制回傳的rows數量
		);
 
		// 注意:不寫會出錯
		if (cursor != null) {
			cursor.moveToFirst();	//將指標移到第一筆資料
		}
		return cursor;
	}

新增

1
2
3
4
5
6
7
8
	//新增一筆記錄,成功回傳rowID,失敗回傳-1
	public long create(String name, String value) {
		ContentValues args = new ContentValues();
		args.put("name", name);
		args.put("value", value);
 
		return db.insert("table_name", null, args);
    }

刪除

1
2
3
4
5
6
7
	//刪除記錄,回傳成功刪除筆數
	public int delete(long rowId) {
		return db.delete("table_name",	//資料表名稱
		"_ID=" + rowId,			//WHERE
		null				//WHERE的參數
		);
	}

修改

1
2
3
4
5
6
7
8
9
10
11
	//修改記錄,回傳成功修改筆數
	public int update(long rowId, String value) {
		ContentValues args = new ContentValues();
		args.put("value", value);
 
		return db.update("table_name",	//資料表名稱
		args,				//VALUE
		"_ID=" + rowId,			//WHERE
		null				//WHERE的參數
		);
	}

 

從SQLite類別裡抓回來的資料是 Cursor 物件,可以把它想像成一張資料表,基本的操作方式如下(詳細方法請參考官方網站):

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
	private SQLite dbHelper;
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
 
		dbHelper = new SQLite(this);
		Cursor cursor = dbHelper.getAll();	//取得SQLite類別的回傳值:Cursor物件
		int rows_num = cursor.getCount();	//取得資料表列數
 
		if(rows_num != 0) {
			cursor.moveToFirst();			//將指標移至第一筆資料
			for(int i=0; i<rows_num; i++) {
				int id = cursor.getInt(0);	//取得第0欄的資料,根據欄位type使用適當語法
				String name = cursor.getString(1);
				int value = cursor.getInt(2);
 
				cursor.moveToNext();		//將指標移至下一筆資料
			}
		}
		cursor.close();		//關閉Cursor
		dbHelper.close();	//關閉資料庫,釋放記憶體
	}

如果是使用 ListActivity 讀取資料庫,則使用的語法如下):

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
	private SQLite dbHelper;
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
 
		// 無記錄
		getListView().setEmptyView(findViewById(R.id.empty));
 
		// 有記錄
		dbHelper = new SQLite(this);
		Cursor cursor = dbHelper.getAll();	//取得SQLite類別的回傳值:Cursor物件
 
		startManagingCursor(cursor);
		String[] from = new String[]{"name", "value"};	//讀取資料庫欄位
		int[] to = new int[]{android.R.id.text1, android.R.id.text2};	//目標ListView欄位名稱(固定)
 
		SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, 
					android.R.layout.simple_list_item_2, 
					cursor, from, to);
		setListAdapter(adapter);
	}

 

REF:http://www.moke.tw/wordpress/computer/advanced/177

文章標籤
全站熱搜
創作者介紹
創作者 Eason 的頭像
Eason

jason71248的部落格

Eason 發表在 痞客邦 留言(0) 人氣(1,392)