banner
jzman

jzman

Coding、思考、自觉。
github

Android JetpackコンポーネントのPaging Libraryについて

この記事を読む前に、同シリーズの Android Jetpack コンポーネントに関する記事を以下に示します:

この記事では Paging Library の使用について説明します。そのソースコードの解析は次の記事で紹介します。Paging Library コンポーネントは Android Jetpack の一部であり、Google が提供する公式のページネーションコンポーネントです。プロジェクトで Google が新たに提供する公式のアーキテクチャコンポーネント(LiveData、Lifecycle、ViewModel など)を使用している場合は、このページネーションコンポーネントをプロジェクトに導入することを検討できます。その利点は、データをシームレスに追加読み込みでき、ユーザー体験を向上させることができる点です。

Paging コンポーネントを使用してデータをページングして読み込むプロセスを簡単に説明します。DataSource はネットワークまたはデータベースからデータを読み込み、データを PagedList に格納します。submitList を使用してデータを PagedListAdapter に提出し、データが変更されると、バックグラウンドスレッドでデータの差分が計算され、最終的に PagedListAdapter が RecyclerView にデータの更新を通知します。

  1. データの準備
  2. Paging Library コンポーネントの導入
  3. カスタム DataSource の作成
  4. ページングパラメータの設定
  5. データの読み込みと表示
  6. 効果のテスト
  7. Paging Library ソースコードの解析

データの準備#

ここでは、干貨集中营のオープン API を使用してテストを行います。具体的には以下の通りです:

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 を以下のように導入します:

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 を以下のように作成します:

// カスタムDataSource
public class MDataSource extends PageKeyedDataSource<String, DataBean.ResultsBean> {
    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 を作成するためのファクトリを作成します:

// MDataSource作成ファクトリ
public class MDataSourceFactory extends DataSource.Factory<String, DataBean.ResultsBean> {
    public MDataSourceFactory() {
    }

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

ページングパラメータの設定#

ViewModel 内で PagedList.Config を作成し、ページングパラメータを設定します。DataSource ファクトリオブジェクトを作成し、最終的にページングをサポートする LiveData データを生成します。具体的には以下の通りです:

// ViewModel
public class MViewModel extends ViewModel {

    private int pageSize = 20;

    // PagedList設定
    private PagedList.Config config = new PagedList.Config.Builder()
            .setInitialLoadSizeHint(pageSize)//初回読み込み数を設定
            .setPageSize(pageSize)//1ページあたりの読み込み数を設定
            .setPrefetchDistance(2)//次のページデータを事前に読み込むための最後のデータ項目までの距離を設定
            .setEnablePlaceholders(false)//UIプレースホルダーを有効にするかどうかを設定
            .build();
    // DataSource.Factory
    private DataSource.Factory<String,DataBean.Results
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。