分析如何在RecyclerView 如何使用CursorAdapter,實現(xiàn)通過Cursor展示數(shù)據(jù)

之前獲取聯(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()方法暫時替換一下。

3:小功告成

完整代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容