之前獲取聯(lián)系人時,采用的是自定義一個ContentProvider,最近發(fā)現(xiàn)在android 3.0的時候引入了CursorLoader這個概念,通過getLoaderManager().initLoader()初始化,實現(xiàn)LoaderCallbacks回調(diào),就很方便獲取到聯(lián)系人信息。
1:問題
實現(xiàn)LoaderCallbacks的回調(diào)即:
//在這里創(chuàng)建CursorLoader并返回
public Loader<Cursor> onCreateLoader(int id, Bundle args) ;
//在這個回調(diào)中實現(xiàn)數(shù)據(jù)展示
public void onLoadFinished(Loader<Cursor> loader, Cursor data);
//當(dāng)之前創(chuàng)建的CursorLoader被重置,并且數(shù)據(jù)不可用的時候會調(diào)用
public void onLoaderReset(Loader<Cursor> loader) ;
但是這里我們要講的是如何在onLoadFinished()方法中從cursor參數(shù)中獲取數(shù)據(jù),并且展示在RecyclerView中。
2:分析
當(dāng)我們使用ListView 的時候,如果數(shù)據(jù)源來自數(shù)據(jù)庫,經(jīng)常會使用到 SimpleCursorAdapter這個類。這個類繼承了 ResourceCursorAdapter。ResourceCursorAdapter繼承自CursorAdapter。既然這樣,那我們能不能寫一個自定義的CustomCursorAdapter 用來實現(xiàn)在RecyclerView 中展示數(shù)據(jù)呢?事實上是可以的。
這里我們考慮到兼容問題,因此采用v4包下的CursorAdapter:
android.support.v4.widget.CursorAdapter
(1)構(gòu)造方法
當(dāng)我們查看該類的構(gòu)造函數(shù)時,我們會看到以下注釋:
@Deprecated
public CursorAdapter(Context context, Cursor c) {
init(context, c, FLAG_AUTO_REQUERY);
}
對了,正如你所發(fā)現(xiàn),這個方法已經(jīng)被廢棄了,因為當(dāng)我們通過這個函數(shù)用來創(chuàng)建CursorAdapter時,實際上傳入了一個叫做"FLAG_AUTO_REQUERY"的整形flag,這個參數(shù)意味著,將會在application's UI thread 中查詢數(shù)據(jù)。這當(dāng)然是萬萬不能的。
因此我們不得不繼續(xù)看下去
public CursorAdapter(Context context, Cursor c, boolean autoRequery) {
init(context, c, autoRequery ? FLAG_AUTO_REQUERY : FLAG_REGISTER_CONTENT_OBSERVER);
}
public CursorAdapter(Context context, Cursor c, int flags) {
init(context, c, flags);
}
這時我們發(fā)現(xiàn),其實在官方推薦的兩個構(gòu)造函數(shù)中,其實都是調(diào)用了這個函數(shù)
//這個函數(shù)主要是根據(jù)調(diào)用者傳入的flag來判斷,是否應(yīng)該啟用數(shù)據(jù)觀察者,是否在主線程中查詢
void init(Context context, Cursor c, int flags)
我們當(dāng)然不能在主線程中查詢數(shù)據(jù),因此這個傳入的flag,應(yīng)該是:
/**
* If set the adapter will register a content observer on the cursor and will call
* {@link #onContentChanged()} when a notification comes in. Be careful when
* using this flag: you will need to unset the current Cursor from the adapter
* to avoid leaks due to its registered observers. This flag is not needed
* when using a CursorAdapter with a
* {@link android.content.CursorLoader}.
*/
public static final int FLAG_REGISTER_CONTENT_OBSERVER = 0x02;
(2):重寫的方法
1:由于CursorAdapter 是為ListView服務(wù),因此繼承了BaseAdapter。但是我們是要自定義一個為RecyclerView 服務(wù)的adapter,因此在重寫的方法中需要格外注意。
@Override
public boolean hasStableIds() {
return true;
}
由于在RecyclerView.Adapter 中hasStableIds()已經(jīng)不能被重寫,因此這里應(yīng)該在init()的最后通過set函數(shù)給予更改:
setHasStableIds(true);
2:在BaseAdapter中,展示view,需要通過getview方法返回。由于在RecyclerView.Adapter 中不再提供。因此我們需要額外添加一個
@Override
public void onBindViewHolder(VH holder, int position) {
if (!mDataValid) {
throw new IllegalStateException("this should only be called when the cursor is valid");
}
if (!mCursor.moveToPosition(position)) {
throw new IllegalStateException("couldn't move cursor to position " + position);
}
//虛函數(shù),需要調(diào)用者實現(xiàn)
onBindViewHolder(holder, mCursor);
}
3:最后注意一點就是在swapCursor() 方法中,notify the observers about the lack of a data set 時調(diào)用了
notifyDataSetInvalidated();
這個方法是告訴綁定的觀察者,某些潛在的數(shù)據(jù)已經(jīng)不可用了。
我們可以通過notifyDataSetChanged()方法暫時替換一下。