Cursor記錄集游標、ListView和SimpleCursorAdapter、ListView數據動態更新
Email:chentravelling@163.com
為什么要把**Cursor、ListView、SimpleCursorAdapter**這三個放在一起來講呢?實在是因為在使用的時候,這三個太緊密相關了。
環境:
IDE:Android Studio
JDK:1.8
系統:win7 64位
### 一、Cursor
在android系統中使用SQLite數據庫,那么Cursor就會經常使用,使用方式大概如下:
~~~
SQLiteDatabase db;
//...
String sql = "select * from 表";
Cursor cursor = db.rawQuery(sql,null);
~~~
即我們查詢數據返回得到的是一個封裝成Cursor的對象,這就是一個記錄集,包含了所有查詢得到的記錄。那么關于Cursor類簡單介紹一下幾種關鍵方法:
首先,我們要使用Cursor記錄集游標,就必須知道查詢語句中表的字段名、數據類型。
- moveToFirst()游標移動到第一行,一般用這個方法判斷查詢結果是否為空
> 使用方法:
~~~
if(cursor.moveToFirst()==false)
return;
~~~
- moveToLast()游標移動到最后一行
- moveToPosition(int position)游標移動到指定行
- moveToPrevious()游標移動到前一行
- moveToNext()游標移動到下一行,主要用于遍歷獲取數據
> 使用方法:
~~~
List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();
Map<String,Object> map;
while (cursor.moveToNext())
{
map = new HashMap<String, Object>();
map.put("name",cursor.getString(cursor.getColumnIndex("name")));
map.put("phone",cursor.getString(cursor.getColumnIndex("phone")));
map.put("_id",cursor.getString(cursor.getColumnIndex("_id")));
list.add(map);
}
~~~
- getColumnIndex(String columnName)獲取指定列在cursor記錄集中的位置
- getString(int position)獲取指定位置的數據
- getColumnName(int columnIndex)獲取指定列的字段名
- getColumnCount()獲得列的總數
- getCount()獲取cursor記錄集的行數
- close()關閉游標,釋放資源
- isBeforeFirst()游標是否指向第一行
- isAfterLast()游標是否指向最后一行
使用方法:
結合isBeforeFirst()、isAfterLast()、moveToNext()三個方法,我們將可以通過for循環來遍歷整個記錄集
~~~
for(cursor.moveToFirst();!cursor.isAfterLast();cursor.moveToNext())
{
//獲取數據,和while()循環一樣;
}
~~~
- isClosed()是否關閉游標
> 還有一些其他方法吧,暫時沒有用過,所以就不羅列了,上面已經把非常常用的方法列舉了。
### 二、ListView和SimpleCursorAdapter
當我們從數據庫中查到了數據以后,一般就會用作界面顯示,那么ListView就會經常用到。那么我分三部分講:1)用于顯示數據適配器;2)數據庫中數據更新后,ListView也更新。首先我們需要三個元素:ListView、adapter即適配器,用于將數據映射到ListView中、數據。
1)常用方法,根據適配器不一樣,或者數據不一樣,我們要選擇的方法也不一樣。一般分為三種:**ArrayAdapter、SimpleAdapter和SimpleCursorAdapter**。第一種最簡單 ,只能用于顯示一行文字,第二種擴展性更好,支持自定義,第三種主要適用于Cursor記錄集游標。對于第一種適配器,本人沒有上代碼測試過,所以就不講了。
- SimpleAdapter
很好的擴展性,可以顯示圖片、各種控件等等。
~~~
public class ShowAddressActivity extends ListActivity {
private AddressDAO addressDAO;
private SimpleAdapter adapter;
private Cursor cursor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//查數據庫返回所有聯系人
addressDAO = new AddressDAO(this);
cursor = addressDAO.query();
List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();
Map<String,Object> map;
//遍歷數據
while (cursor.moveToNext())
{
map = new HashMap<String, Object>();
map.put("name",cursor.getString(cursor.getColumnIndex("name")));
map.put("phone",cursor.getString(cursor.getColumnIndex("phone")));
map.put("_id",cursor.getString(cursor.getColumnIndex("_id")));
list.add(map);
}
adapter = new SimpleAdapter(this,list,R.layout.address_list,new String[]{"_id","name","phone"},new int[]{R.id.id,R.id.name,R.id.phone});
setAdapter(adapter);
~~~
首先我們需要把查詢的數據從cursor游標再次封裝到有HashMap構成的list中,然后再使用new SimpleAdapter();將數據映射到xml文件中,完成適配:映射規則如下圖:

- SimpleCursorAdapter
~~~
public class ShowAddressActivity extends ListActivity {
private AddressDAO addressDAO;
private SimpleCursorAdapter adapter;
private Cursor cursor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.show_address);
//查數據庫返回所有聯系人
addressDAO = new AddressDAO(this);
cursor = addressDAO.query();
adapter = new SimpleCursorAdapter(this,R.layout.address_list,cursor,new String[]{"_id","name","phone"},new int[]{R.id.id,R.id.name,R.id.phone});
ListView listView = (ListView)findViewById(android.R.id.list);
listView.setAdapter(adapter);
//..
}
~~~
其中涉及到了兩個xml文件:show_address.xml和address_list.xml,布局代碼如下:
(1)show_address.xml:包含一個搜索框、一個增加按鈕和一個ListView
~~~
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:context="com.s201525015.chen.addresslist.ShowAddressActivity">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="1">
<EditText
android:layout_width="279dp"
android:layout_height="60dp"
android:hint="搜索聯系人"
android:id="@+id/search"
android:layout_weight="0.65" />
<Button
android:layout_width="55dp"
android:layout_height="45dp"
android:text="增加"
android:id="@+id/addButton" />
</LinearLayout>
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@android:id/list">
</ListView>
</LinearLayout>
~~~
(2)address_list.xml:主要包含一個隱藏域id、分別顯示name和phone的TextView
~~~
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/id"
android:layout_weight="1"
android:visibility="gone"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/name"
android:layout_weight="1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/phone" />
</LinearLayout>
</LinearLayout>
~~~
其中這兩個xml文件結合activity中的代碼可以看出其中的關系:首先是將數據通過適配器映射到address_list.xml文件上,然后在show_address.xml中的ListView中加入完成映射后的adapter用于顯示數據。
這里也要提醒一個問題:findViewById(R.id.list)默認的是在當前頁面中尋找id為list的控件,也就是說在setContentView(XXX),那么只會在XXX.xml文件中查找id為list的控件。如果我們setContentView(A),卻需要獲取B.xml中的控件就需要先指定頁面,再查找:
指定頁面為show_address.xml:
~~~
ListView listAddress = (ListView) View.inflate(this,R.layout.show_address,null).findViewById(android.R.id.list);
~~~
### 三、使用SimpleCursorAdapter,ListView數據更新
~~~
private class RefresList extends AsyncTask<Void,Void,Cursor>
{
protected Cursor doInBackground(Void... params) {
Cursor newCursor = addressDAO.query();
return newCursor;
}
protected void onPostExecute(Cursor newCursor) {
adapter.changeCursor(newCursor);
cursor.close();
cursor = newCursor;
}
}
~~~
在數據發生變化的時候,調用new RefreshList().execute()即可。比如在一個點擊事件中,添加一個數據后,寫入數據庫表中,然后執行new RefreshList().execute();即可更新ListView。還有其他一些方式,暫時不會~
### 四、提示
在這里重點提示一下SimpleAdapter和SimpleCursorAdapter,這兩個適配器的重要區別:
1)如果使用后者,數據庫表中的字段必須有_id,是否一定要為主鍵,我不敢確定。
2)前者映射時數據類型是map構成的list,后者是cursor。