1. 程式人生 > >Android學習筆記 四二 SQLite ListView ContextMenu

Android學習筆記 四二 SQLite ListView ContextMenu

繼續上一個例子,結合ListView中對SQLite進行操作。

通過CursorAdapter在ListView中的資料呈現

在上一個例子中,我們可以對SQLite中的資料庫進行增刪改查,將資料讀到遊標Cursor中,然後一一讀出。在Android中可以通過CursorAdapter直接將資料對映到ListView中,如下處理:

public class Chapter22Test1 extends ListActivity{    private SQLiteDatabase  db = null;    private Cursor cursor = null;        private SimpleCursorAdapter

adapter = null;    protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);        db= (new Chapter22Db (getApplicationContext())).getWritableDatabase();            cursor =db.rawQuery("SELECT _id,Name,Weight from mytable ORDER BY Weight", null);        //layout/chapter_22_test1.xml的Android XML檔案定義了ListView中每個單元的排列方式,每個單元R.id.c22_name和R.id.c22_gravity都是TextView,分列左右
        adapter = new SimpleCursorAdapter(this,                R.layout.chapter_22_test1,                 cursor,                 new String[]{"Name","Weight"},//遊標資料的名稱,實際是Table列名字                new int[]{R.id.c22_name, R.id.c22_gravity});//對應的UI微件的id        setListAdapter(adapter);    }    protected void onDestroy() {        super.onDestroy();
        cursor.close();  //我們在onCreate()中沒有關閉遊標,因為需要和ListView進行資料關聯,關閉curosr,會導致List無資料,故在最後釋放資源        db.close(); //斷開和資料庫的連線,釋放相關資源    }}

更新資料(以增加為例)

我們要實現:通過Menu彈出選單,有一個為增加,按之,彈出一個Dialog,可以在當中填入資料,按Dialog的確定按鍵,在SQLite資料庫的表格mytable中加入相關的資料,並且同步ListView的顯示。

第二步:在add()中,要完成彈出指定格式的Dialog,採用AlertDialog的方式,Dialog的格式在xml中給出。處理方式之前都學過,但是沒有合併使用的例子,包括Dialog的格式,同ListView中自定義元素的格式一樣,採用LayoutInflater。具體如下:

private void add(){    //步驟2.1:通過LayoutInflater從Android的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) {            EditText nameView = (EditText)addView.findViewById(R.id.c22_name);            EditText weigthView = (EditText)addView.findViewById(R.id.c22_weight);            // addData是下面步驟三,實現SQLite的資料更新和ListView的顯示同步add(name,weight);            addData(nameView.getText().toString(), new Float(weigthView.getText().toString()).floatValue());        }    })    .setNegativeButton("取消",null)    .show();}

第三步:更新資料庫和同步ListView,具體如下:

    private void addData(String name ,float weight){        /* 略去資料的判斷,例如如果name一樣,採用update的方式等等*/        //步驟3.1 在資料庫表格中新增資料        ContentValues values = new ContentValues(2);        values.put("Name",name);        values.put("Weight",weight);        db.insert("mytable","Name",values);        //步驟3.2 同步ListView,更新遊標的資訊        cursor.requery();    }

非同步後臺同步資料

在上面的例子,貌似可以,而且的確是可以,但是在Android的API文件中,Cursor的方法requery()這樣寫道:This method is deprecated.Don't use this. Just request a new cursor, so you can do this asynchronously and update your list view once the new cursor comes back. 這提示我們風險的存在,如果資料量大,會導致重寫讀取的事件長(也就是requery()的執行時間)。雖然手機是人手操作,互動頻率較低,在資料庫資料少的時候,例如上面的例子,我們仍然可以安全地使用requery。但是對於具有大量資料時,我們就需要修改上面的程式。

修訂的方式步驟如下:1,通過後臺執行緒來讀取資料庫;2、通過更換cursor來更新ListView,具體如下:

//步驟1:通過後臺執行緒AsyncTask來讀取資料庫,放入更換Cursorprivate class RefreshList extends AsyncTask<Void, Void ,Cursor>{    //步驟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的資訊,採用CusorApater其實很簡單,換cursor就可以        cursor.close();        cursor = newCursor;    }         }//步驟2:取締requrey的方式,採用後臺執行緒更新形式private void addData(String name ,float weight){     ... ...    //cursor.requery();    new RefreshList().execute();}

通過ContextMenu來刪除ListView的資料

ContextMenu使用者手指長按某個View觸發的選單,見Android 學習筆記(二七):Menu。這裡通過這個例子詳細展開。實現場景:使用者長按某個List元素,則彈出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 ,在cursorAdaptor中,實際就是表格的_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-linux_x86/platform-tools目錄下面有adb命令,使用adb shell,可提供模擬器的console視窗。資料庫檔案存放的位置為/data/data/your.app.package/databases/your-db-name,進入相關的目錄,可以使用#sqlite3 your-db-name,進入相關的資料庫,可以在裡面執行SQL語句,例如在整個例子中,通過#.schema來查看錶格的格式,通過#select * from mytable;可以顯示資料庫的內容。