Android Jetpack元件之Paging Library使用篇

語言: CN / TW / HK

highlight: androidstudio theme: jzman


PS:原文首發於微信公眾號:躬行之

閱讀本文之前,可先閱讀同系列 Android Jetpack 元件文章如下 :

本文將介紹 Paging Library 庫的使用,其原始碼解析將在下篇文章中介紹,Paging Library 元件是 Android Jetpack 的一部分,是 Google 退出的官方分頁元件,如果專案中使用了 Google 新推出的官方架構元件,如 LiveData、Lifecycle、ViewModel 等,就可以嘗試將該分頁元件引入自己的專案,它的優點是無痕載入更多資料,一定程度上提高使用者體驗。

簡述一下使用 pageing 元件分頁載入資料的過程,DataSource 負責從網路或資料庫載入資料,將資料儲存在 PagedList 中,使用 submitList 提交資料到 PagedListAdapter,當資料發生變化時會在後臺執行緒中計算資料差異,最後 PagedListAdapter 通知 RecyclerView 更新資料。

  1. 準備資料
  2. 引入Paging Library元件
  3. 自定義DataSource
  4. 配置分頁引數
  5. 載入顯示資料
  6. 測試效果
  7. Paging Library原始碼解析

準備資料

這裡使用乾貨集中營的開源 Api 來進行測試,具體如下:

java public interface CommonAPI { // 這裡使用乾貨集中營開源API:http://gank.io/api/search/query/listview/category/Android/count/10/page/1 @GET("api/search/query/listview/category/Android/count/8/page/{page}") Call<List<DataBean.ResultsBean>> getArticleList1(@Path("page") int page); }

引入Paging Library元件

引入 Paging Library 庫如下:

java def paging_version = "2.1.0" // androidx implementation "androidx.paging:paging-runtime:$paging_version" // 老版本 (page library 2.0.0-rc01) implementation "android.arch.paging:runtime:$paging_version"

這裡使用的時 androidx 最新版本。

自定義DataSource

自定義 DataSource 載入資料,這裡載入的網路資料,使用 PageKeyedDataSource 更合適,繼承 PageKeyedDataSource 自定義 DataSource 如下:

```java // 自定義DataSource public class MDataSource extends PageKeyedDataSource { private static final String TAG = MDataSource.class.getSimpleName();

private int mPage = 1;

public MDataSource() {
}

// 初始化
@Override
public void loadInitial(@NonNull LoadInitialParams<String> params,
                        @NonNull final LoadInitialCallback<String, DataBean.ResultsBean> callback) {
    Log.i(TAG, "--loadInitial-->");
    CommonAPI api = RetrofitApi.getInstance().mRetrofit.create(CommonAPI.class);

    Call<List<DataBean.ResultsBean>> call = api.getArticleList1(mPage);
    call.enqueue(new Callback<List<DataBean.ResultsBean>>() {
        @Override
        public void onResponse(Call<List<DataBean.ResultsBean>> call, Response<List<DataBean.ResultsBean>> response) {
            Log.i(TAG, "--onResponse-->" + response.toString());
            if (response.isSuccessful() && response.code() == 200) {
                List<DataBean.ResultsBean> data  = response.body();
                callback.onResult(data, "before", "after");
            }
        }

        @Override
        public void onFailure(Call<List<DataBean.ResultsBean>> call, Throwable t) {
            Log.i(TAG, "--onFailure-->" + t.getMessage());
        }

    });
}

// 載入上一頁
@Override
public void loadBefore(@NonNull LoadParams<String> params,
                       @NonNull LoadCallback<String, DataBean.ResultsBean> callback) {
    Log.i(TAG, "--loadBefore-->" + params.key);
}

// 載入下一頁
@Override
public void loadAfter(@NonNull final LoadParams<String> params,
                      @NonNull final LoadCallback<String, DataBean.ResultsBean> callback) {
    Log.i(TAG, "--loadAfter-->" + params.key);
    mPage++;
    CommonAPI api = RetrofitApi.getInstance().mRetrofit.create(CommonAPI.class);
    Call<List<DataBean.ResultsBean>> call = api.getArticleList1(mPage);
    call.enqueue(new Callback<List<DataBean.ResultsBean>>() {
        @Override
        public void onResponse(Call<List<DataBean.ResultsBean>> call, Response<List<DataBean.ResultsBean>> response) {
            Log.i(TAG, "--onResponse-->" + response.toString());
            if (response.isSuccessful() && response.code() == 200) {
                List<DataBean.ResultsBean> data  = response.body();
                callback.onResult(data, params.key);
            }
        }

        @Override
        public void onFailure(Call<List<DataBean.ResultsBean>> call, Throwable t) {
            Log.i(TAG, "--onFailure-->" + t.getMessage());
        }

    });
}

} ```

很簡單沒有什麼多餘的東西,細節可以參考後文中的原始碼解析,建立一個工廠方便資料變化是建立新的 DataSource 如下:

```java // MDataSource建立工廠 public class MDataSourceFactory extends DataSource.Factory { public MDataSourceFactory() { }

@NonNull
@Override
public DataSource<String, DataBean.ResultsBean> create() {
    MDataSource mDataSource = new MDataSource();
    return mDataSource;
}

} ```

配置分頁引數

在 ViewModel 中建立 PagedList.Config 並進行分頁引數配置,建立 DataSource 工廠物件,最終生成支援分頁的 LiveData 資料,具體參考如下:

```java // ViewModel public class MViewModel extends ViewModel {

private int pageSize = 20;

// PagedList配置
private PagedList.Config config = new PagedList.Config.Builder()
        .setInitialLoadSizeHint(pageSize)//設定首次載入的數量
        .setPageSize(pageSize)//設定每頁載入的數量
        .setPrefetchDistance(2)//設定距離每頁最後資料項來時預載入下一頁資料
        .setEnablePlaceholders(false)//設定是否啟用UI佔用符
        .build();
// DataSource.Factory
private DataSource.Factory<String,DataBean.ResultsBean> factory = new MDataSourceFactory();

// LiveData
private LiveData<PagedList<DataBean.ResultsBean>> mPagedList = new LivePagedListBuilder<>(factory, config)
        .build();

public LiveData<PagedList<DataBean.ResultsBean>> getPagedList() {
    return mPagedList;
}

} ```

載入顯示資料

這裡使用 LiveData 監聽載入的資料,然後使用 sumbitList 將資料提交給 PagedListAdapter,會在後臺執行緒中對比新舊資料的差異,最後更新 RecyclerView ,具體如下:

```java public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); private RecyclerView mRecyclerView; private ArticleAdapter mAdapter; private MViewModel mViewModel;

private static DiffUtil.ItemCallback<DataBean.ResultsBean> itemCallback = new DiffUtil.ItemCallback<DataBean.ResultsBean>() {
    @Override
    public boolean areItemsTheSame(@NonNull DataBean.ResultsBean oldItem, @NonNull DataBean.ResultsBean newItem) {
        return oldItem.getGanhuo_id() == newItem.getGanhuo_id();
    }

    @Override
    public boolean areContentsTheSame(@NonNull DataBean.ResultsBean oldItem, @NonNull DataBean.ResultsBean newItem) {
        return oldItem.equals(newItem);
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mRecyclerView = findViewById(R.id.rvData);
    mAdapter = new ArticleAdapter(itemCallback);
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
    mRecyclerView.setAdapter(mAdapter);
    ViewModelProvider mViewModelProvider = new ViewModelProvider(this,
            new ViewModelProvider.AndroidViewModelFactory(getApplication()));
    mViewModel = mViewModelProvider.get(MViewModel.class);
}

public void getData(View view) {
    mViewModel.getPagedList().observe(this, new Observer<PagedList<DataBean.ResultsBean>>() {
        @Override
        public void onChanged(PagedList<DataBean.ResultsBean> dataBeans) {
            Log.i(TAG, "--onChanged-->");
            mAdapter.submitList(dataBeans);
        }
    });
}

} ```

測試效果

可以關注公眾號:躬行之 交流學習。