在Android 查詢數據是通過Cursor 類來實現的。當我們使用 SQLiteDatabase.query()方法時,就會得到Cursor對象, Cursor所指向的就是每一條數據。
Cursor 位於 android.database.Cursor類,可見出它的設計是基於數據庫服務產生的。
子類有:
- AbstractCursor
- AbstractWindowedCursor
- CrossProcessCursor
- CursorWrapper
- MatrixCursor
- MergeCursor
- MockCursor
- SQLiteCursor
1.Cursor必知
- Cursor 是每行的集合。
- 使用 moveToFirst() 定位第一行。
- 你必須知道每一列的名稱。
- 你必須知道每一列的數據類型。
- Cursor 是一個隨機的數據源。
- 所有的數據都是通過下標取得。
2.Cursor的重要方法
- close()
關閉游標,釋放資源 - copyStringToBuffer(int columnIndex, CharArrayBuffer buffer)
在緩沖區中檢索請求的列的文本,將將其存儲 - getColumnCount()
返回所有列的總數 - getColumnIndex(String columnName)
返回指定列的名稱,如果不存在返回-1 - getColumnIndexOrThrow(String columnName)
從零開始返回指定列名稱,如果不存在將拋出IllegalArgumentException 異常。 - getColumnName(int columnIndex)
從給定的索引返回列名 - getColumnNames()
返回一個字符串數組的列名 - getCount()
返回Cursor 中的行數 - moveToFirst()
移動光標到第一行 - moveToLast()
移動光標到最后一行 - moveToNext()
移動光標到下一行 - moveToPosition(int position)
移動光標到一個絕對的位置 - moveToPrevious()
移動光標到上一行
3.如何使用
(1)判斷cursor是否為空
if (cur.moveToFirst() == false) { //為空的Cursor return; }
(2)獲取列值
*獲取單個的列值 //獲取列名為name的列索引 int nameColumnIndex = cur.getColumnIndex(People.NAME); //由列索引獲取姓名 String name = cur.getString(nameColumnIndex); *循環 Cursor 取出我們需要的數據 while(cur.moveToNext()) { //光標移動成功 String email = cursor.getString(cursor.getColumnIndex(RuiXin.EMAIL)); startManagingCursor(cursor); //查找后關閉游標 //把數據取出 }
cur.moveToNext() 為假時將跳出循環,即 Cursor 數據循環完畢
3.補充
Activity.startManagingCursor方法:
將獲得的Cursor對象交與Activity管理,這樣Cursor對象的生命周期便能與當前的Activity自動同步,省去了自己對Cursor的管理。
1.這個方法使用的前提是:游標結果集里有很多的數據記錄。
public void queryTheCursor(View view) { 02 Cursor c = mgr.queryTheCursor(); 03 startManagingCursor(c); //托付給activity根據自己的生命周期去管理Cursor的生命周期 04 CursorWrapper cursorWrapper = new CursorWrapper(c) { 05 @Override 06 public String getString(int columnIndex) { 07 //將簡介前加上年齡 08 if (getColumnName(columnIndex).equals("info")) { 09 int age = getInt(getColumnIndex("age")); 10 return age + " years old, " + super.getString(columnIndex); 11 } 12 return super.getString(columnIndex); 13 } 14 }; 15 //確保查詢結果中有"_id"列 16 SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, 17 cursorWrapper, new String[]{"name", "info"}, new int[]{android.R.id.text1, android.R.id.text2}); 18 ListView listView = (ListView) findViewById(R.id.listView_db); 19 listView.setAdapter(adapter); 20 }
4.補充2 SimpleCursorAdapter
(轉http://www.nowamagic.net/academy/detail/50350111)
一般在做網頁的時候,要顯示一個列表的數據,一般是對一個list的類進行循環,輸出一大串的HTML字符串。數據比較多的話就會分頁,比如一頁10條記錄,去數據庫查詢的時候就會limit 10條記錄,速度非常快。
但在 Android中遇到幾千條數據的時候,上下滑動,跟幾十條數據的滑動流暢程度差不多,就是剛開始載入速度不一樣。對Android 中的Adapter 數據綁定,進行Log輸出后,發現是邊滑動,數據邊綁定的,並不是有多少數據一次性綁定完。但是數據一般是用sql 語句一次性查詢出來,這點跟Web中的還是有點區別。
Android中ListView一般跟Cursor和Adapter有關。很多東西google都幫你弄好了,你只需要按照它約定的弄就行了。“你動不了Application Framework 的大結構,也不需要動。這是福利不是約束”。
SimpleCursorAdapter 的函數定義是:
SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to)
第二個layout的參數是ListView中單行的布局, c是你數據的游標。剛開始其實from和to比較讓人不熟悉,From是你查詢出的數據,to是單行布局中的單獨控件,一對一的關系,用起來非常方便。比如:
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.provice_list_item, cursor, new String[] {Location.PROVICE, Location.CITY }, new int[] { R.id.princeTextView,android.R.id.text1 });
寫好Adapter,基本上大部分工作已經完成,只需要給你的listview設置這個adapter就行了。一個顯示數據的列表就完成了。
需要注意的是SimpleCursorAdapter的應用,當我們使用這個適配器時,我們必須先得到一個Cursor對象,這里面有幾個問題:如何管理Cursor的生命周期,如果包裝Cursor,Cursor結果集都需要注意什么。
如果手動去管理Cursor的話會非常的麻煩,還有一定的風險,處理不當的話運行期間就會出現異常,幸好Activity為我們提供了startManagingCursor(Cursor cursor)方法,它會根據Activity的生命周期去管理當前的Cursor對象。
startManagingCursor
下面是 startManagingCursor 方法的說明:
文中提到,startManagingCursor方法會根據Activity的生命周期去管理當前的Cursor對象的生命周期,就是說(1)當Activity停止時他會自動調用Cursor的deactivate方法,禁用游標,(2)當Activity重新回到屏幕時它會調用Cursor的requery方法再次查詢,(3)當Activity摧毀時,被管理的Cursor都會自動關閉釋放。
如何包裝Cursor?我們會使用到CursorWrapper對象去包裝我們的Cursor對象,實現我們需要的數據轉換工作,這個CursorWrapper實際上是實現了Cursor接口。我們查詢獲取到的Cursor其實是Cursor的引用,而系統實際返回給我們的必然是Cursor接口的一個實現類的對象實例,我們用CursorWrapper包裝這個實例,然后再使用SimpleCursorAdapter將結果顯示到列表上。
Cursor結果集需要注意些什么:一個最需要注意的是,在我們的結果集中必須要包含一個“_id”的列,否則SimpleCursorAdapter就會翻臉不認人,為什么一定要這樣呢?因為這源於SQLite的規范,主鍵以“_id”為標准。
解決辦法有三:
- 第一,建表時根據規范去做;
- 第二,查詢時用別名,例如:SELECT id AS _id FROM person;
- 第三,在CursorWrapper里做文章:
如果試圖從CursorWrapper里獲取“_id”對應的列索引,我們就返回查詢結果里“id”對應的列索引即可。