這個例子是App應用程式中對資料存取很常見之技巧,要融會貫通在日後開發相類似時可用,通常與資料庫扯上關係是要通過CursorAdapter作為中間媒介,其它相關之Adapter類型都無法達到此要求(因資料存取作業須有指標配合方能運作),至於資料呈現本例採用最常見之ListView來顯示。
主類之代碼如下:
public
class DbaccessActivity extends ListActivity{
//建立Gloabal變數
private SQLiteDatabase db = null;
private Cursor cursor = null;
private SimpleCursorAdapter adapter = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
private SQLiteDatabase db = null;
private Cursor cursor = null;
private SimpleCursorAdapter adapter = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//取用可寫入型資料庫
db= (new Dbcls (getApplicationContext())).getWritableDatabase(); // 此Dbcls為繼承SQLiteOpenHelper抽象類別之子類
db= (new Dbcls (getApplicationContext())).getWritableDatabase(); // 此Dbcls為繼承SQLiteOpenHelper抽象類別之子類
//輸入SQL Commnad指令取用資料(RAW 方式)
cursor =db.rawQuery("SELECT _id,Name,Weight from mytable ORDER BY Weight", null);
//在layout/access.xml定義了ListView中Item之佈局,其Item使用元件之id為R.id.name和R.id.gravity均為TextView,分列左右
//建立CursorAdapter
adapter = new SimpleCursorAdapter(this, R.layout.access, cursor, new String[]{"Name","Weight"}, new int[]{R.id.name, R.id.gravity});//前為指定指標資料的名稱(含類型定義),實際為Table欄位名稱,後為,對應的UI控件的id
//將CursorAdapter設入ListAdapter中(因本例extends ListActivity)
setListAdapter(adapter);
cursor =db.rawQuery("SELECT _id,Name,Weight from mytable ORDER BY Weight", null);
//在layout/access.xml定義了ListView中Item之佈局,其Item使用元件之id為R.id.name和R.id.gravity均為TextView,分列左右
//建立CursorAdapter
adapter = new SimpleCursorAdapter(this, R.layout.access, cursor, new String[]{"Name","Weight"}, new int[]{R.id.name, R.id.gravity});//前為指定指標資料的名稱(含類型定義),實際為Table欄位名稱,後為,對應的UI控件的id
//將CursorAdapter設入ListAdapter中(因本例extends ListActivity)
setListAdapter(adapter);
}
protected void onDestroy() {
super.onDestroy();
cursor.close(); //釋放Cursor資源
db.close(); //關閉資料庫的連接以釋放相關資源
}
}
protected void onDestroy() {
super.onDestroy();
cursor.close(); //釋放Cursor資源
db.close(); //關閉資料庫的連接以釋放相關資源
}
}
運行一下程式展示結果如下:
Ø
資料異動作業(本例以”加入資料”為例作說明應用,至於”刪除資料”則採用ContextMenu方式進行)
通過Menu彈出功能表,按「Add」按鈕以彈出一個Dialog,可在此當中填入相關資料,之後使其在SQLite資料庫mytable表格中加入所填之資料,並且同步ListView的畫面顯示。茲將需求之作法列述如下:
1.
建立OptionsMenu功能表物件,並在其內設置「Add」按鍵,當按下時觸發執行add()方法。
2. 在add()方法中彈出指定之AlertDialog(格式在xml中定義)以進行 加入資料處理作業,具體代碼如下:
private void add(){
//步驟2.1:通過LayoutInflater從XML檔中生成View
LayoutInflater inflater = LayoutInflater.from(this);
final View addView = inflater.inflate(R.layout.add_dialgo,null);
//步驟2.2:通過AlertDialog彈出對話方塊,並且在第一個button,即PositiveButton設定監聽事件
new AlertDialog.Builder(this)
.setTitle("添加框")
.setView(addView)
.setPositiveButton("確定", new DialogInterface.OnClickListener() {
//因希望由addView中得到資料,但這個inner class只能獲取final的值,所以須將addView設置為final,也就是所有addView的位址是固定的,而不是動態生成。
public void onClick(DialogInterface dialog, int which) {
//取得UI介面之控件
EditText nameView = (EditText)addView.findViewById(R.id.name);
EditText weigthView = (EditText)addView.findViewById(R.id.weight);
// addData是下面步驟3之自訂方法,實現SQLite的資料更新和ListView的顯示同步add(name,weight)方法;
addData(nameView.getText().toString(), new Float(weigthView.getText().toString()).floatValue());
}
})
.setNegativeButton("取消",null)
.show();
}
//步驟2.1:通過LayoutInflater從XML檔中生成View
LayoutInflater inflater = LayoutInflater.from(this);
final View addView = inflater.inflate(R.layout.add_dialgo,null);
//步驟2.2:通過AlertDialog彈出對話方塊,並且在第一個button,即PositiveButton設定監聽事件
new AlertDialog.Builder(this)
.setTitle("添加框")
.setView(addView)
.setPositiveButton("確定", new DialogInterface.OnClickListener() {
//因希望由addView中得到資料,但這個inner class只能獲取final的值,所以須將addView設置為final,也就是所有addView的位址是固定的,而不是動態生成。
public void onClick(DialogInterface dialog, int which) {
//取得UI介面之控件
EditText nameView = (EditText)addView.findViewById(R.id.name);
EditText weigthView = (EditText)addView.findViewById(R.id.weight);
// addData是下面步驟3之自訂方法,實現SQLite的資料更新和ListView的顯示同步add(name,weight)方法;
addData(nameView.getText().toString(), new Float(weigthView.getText().toString()).floatValue());
}
})
.setNegativeButton("取消",null)
.show();
}
3. 實現更新資料庫和同步ListView之顯示,具體代碼如下:
private void addData(String name
,float weight){
/* 略去資料的判斷,例如如果name一樣,採用update的方式等等*/
//步驟3.1 在資料庫表格中添加資料
ContentValues values = new ContentValues(2); //指定具2個值域
values.put("Name",name);
values.put("Weight",weight);
db.insert("mytable","Name",values);
//步驟3.2 同步ListView(更新指標的資訊)
cursor.requery();
}
/* 略去資料的判斷,例如如果name一樣,採用update的方式等等*/
//步驟3.1 在資料庫表格中添加資料
ContentValues values = new ContentValues(2); //指定具2個值域
values.put("Name",name);
values.put("Weight",weight);
db.insert("mytable","Name",values);
//步驟3.2 同步ListView(更新指標的資訊)
cursor.requery();
}
Ø 以後臺非同步執行緒進行資料更新與同步顯示
前述例子是採用Cursor之requery()方法來進行資料重整作業,此在資料較少的時候,仍可安全地使用,但是對於具有大量資料時則會有很大風險的存在,其因資料量大會導致重寫讀取事件會進行很長之執行時間,造成使用者體驗感受不佳。其修訂的方式是採用非同步(AsyncTask)技術來改進,思路如下:
1.
通過後臺之執行緒來讀取資料庫;
2.
通過更換新的cursor來更新ListView,具體代碼如下:
//步驟1:通過後臺執行緒AsyncTask來讀取資料庫,放入一個更換新的指標Cursor
private class RefreshList extends AsyncTask { //※此為新技術AsyncTask執行緒之概念
//步驟1.1:在後臺執行緒中進行資料庫讀取,並返回新的指標newCursor
protected Cursor doInBackground(Void... params) {
Cursor newCursor = db.rawQuery("SELECT _id,Name,Weight from mytable ORDER BY Weight", null);
return newCursor;
}
//步驟1.2:執行緒之最後執行步驟,更換adapter的指標,並關閉指標及資料庫以釋放資源
protected void onPostExecute(Cursor newCursor) {
adapter. changeCursor( newCursor); //更新ListView採用之Adapter(※以新的cursor作更換)
cursor.close();
cursor = newCursor;
}
}
//步驟2:取消requrey方式,改採用後臺AsyncTask執行緒進行更新作業
private void addData(String name ,float weight){
... ...
//cursor.requery();
new RefreshList().execute();
}
private class RefreshList extends AsyncTask { //※此為新技術AsyncTask執行緒之概念
//步驟1.1:在後臺執行緒中進行資料庫讀取,並返回新的指標newCursor
protected Cursor doInBackground(Void... params) {
Cursor newCursor = db.rawQuery("SELECT _id,Name,Weight from mytable ORDER BY Weight", null);
return newCursor;
}
//步驟1.2:執行緒之最後執行步驟,更換adapter的指標,並關閉指標及資料庫以釋放資源
protected void onPostExecute(Cursor newCursor) {
adapter. changeCursor( newCursor); //更新ListView採用之Adapter(※以新的cursor作更換)
cursor.close();
cursor = newCursor;
}
}
//步驟2:取消requrey方式,改採用後臺AsyncTask執行緒進行更新作業
private void addData(String name ,float weight){
... ...
//cursor.requery();
new RefreshList().execute();
}
Ø 通過ContextMenu來刪除ListView資料
ContextMenu為使用者手指長按某個View時觸發顯示之功能表,換言之,即當使用者長按ListView中之某個Item元素,則使之彈出ContextMenu功能表,此時選按「Delete」按鈕則會彈出另一個AlertDialog訊息框,請用戶確認是否進行刪除,當確定後將資料從SQLite中刪除,且同步更新ListView之顯示,具體代碼如下:
protected void onCreate(Bundle
savedInstanceState) {
... ... //如前
//步驟1:向ListView註冊Context Menu,當系統檢測到使用者長按某元素時觸發Context Menu
registerForContextMenu(getListView());
}
// 步驟2:創建ContextMenu(同OptionMenu),當使用者長按元素後彈出功能表
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
menu.add(Menu.NONE,DELETE_ID,Menu.NONE,"Delete");
super.onCreateContextMenu(menu, v, menuInfo);
}
//步驟 3: 定義ContextMenu的觸發事件,本例以觸發delete()作舉例說明
public boolean onContextItemSelected(MenuItem item) {
switch(item.getItemId()){
case DELETE_ID:
/* 在此處,我們關鍵引入 AdapterView.AdapterContextMenuInfo來獲取單元的資訊,其參數含有三個重要的資訊,如下:
1、id:The row id of the item for which the context menu is being displayed ,在cursorAdapter中,實際指的就是表格的_id序號;
2、position:為list中元素的順序位置;
3、view:為list中點擊元素的View,透過view可以獲取裡面的顯示的資訊 */
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
delete(info.id);
return true;
default:
break;
}
return super.onContextItemSelected(item);
}
//步驟4: 對觸發彈出功能框(和Add的相似),當確定後即進行更新資料庫和同步ListView的顯示,其中getNameById是通過id查名字的方法。值得注意的是,為了內部類中使用,delete的參數採用final的形式。
private void delete(final long rowId){
if(rowId>0){
new AlertDialog.Builder(this)
.setTitle("刪除" + getNameById(rowId))
.setPositiveButton("確定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
deleteData(rowId);
}
})
.setNegativeButton("取消", null)
.show();
}
}
private void deleteData(long rowId){
String[] str = {String.valueOf(rowId)};
db.delete("mytable","_id=?",str);
new RefreshList().execute(); //採用後臺方式,當然也可以用crusor.requery()來處理。
}
... ... //如前
//步驟1:向ListView註冊Context Menu,當系統檢測到使用者長按某元素時觸發Context Menu
registerForContextMenu(getListView());
}
// 步驟2:創建ContextMenu(同OptionMenu),當使用者長按元素後彈出功能表
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
menu.add(Menu.NONE,DELETE_ID,Menu.NONE,"Delete");
super.onCreateContextMenu(menu, v, menuInfo);
}
//步驟 3: 定義ContextMenu的觸發事件,本例以觸發delete()作舉例說明
public boolean onContextItemSelected(MenuItem item) {
switch(item.getItemId()){
case DELETE_ID:
/* 在此處,我們關鍵引入 AdapterView.AdapterContextMenuInfo來獲取單元的資訊,其參數含有三個重要的資訊,如下:
1、id:The row id of the item for which the context menu is being displayed ,在cursorAdapter中,實際指的就是表格的_id序號;
2、position:為list中元素的順序位置;
3、view:為list中點擊元素的View,透過view可以獲取裡面的顯示的資訊 */
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
delete(info.id);
return true;
default:
break;
}
return super.onContextItemSelected(item);
}
//步驟4: 對觸發彈出功能框(和Add的相似),當確定後即進行更新資料庫和同步ListView的顯示,其中getNameById是通過id查名字的方法。值得注意的是,為了內部類中使用,delete的參數採用final的形式。
private void delete(final long rowId){
if(rowId>0){
new AlertDialog.Builder(this)
.setTitle("刪除" + getNameById(rowId))
.setPositiveButton("確定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
deleteData(rowId);
}
})
.setNegativeButton("取消", null)
.show();
}
}
private void deleteData(long rowId){
String[] str = {String.valueOf(rowId)};
db.delete("mytable","_id=?",str);
new RefreshList().execute(); //採用後臺方式,當然也可以用crusor.requery()來處理。
}
運行程式顯示效果如下:
Ø 通過模擬器的Console進行資料庫操作
在android-sdk-windows/platform-tools目錄下有個adb命令,於命令模式下輸入adb shell,可提供模擬器的console視窗。資料庫檔存放的位置為/data/data/your.app.package/databases/your-db-name,進入資料庫指定目錄後,可使用#sqlite3
your-db-name即可進入資料庫,在此即可執行SQL語句進行資料處理操作,如通過#.schema來查看表格的格式,通過#select *
from mytable;可以顯示資料庫的內容。
.png)





0 意見:
張貼留言