SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

アプリケーション開発の最新トレンド

Androidのページング処理のライブラリ「Paging 3」の移行と実装のポイント

  • X ポスト
  • このエントリーをはてなブックマークに追加

APIから取得したデータを表示するだけの場合

 この要件の際はPagingSourceを実装して、PagerのpagingSourceFactoryに指定するだけで実装可能です。

 実装の完成系はサンプルコードのmasterブランチをご覧ください

PagingSourceの実装

 PagingSourceで実装する必要があるメソッドは2つあります。

  • getRefreshKeyメソッド: refreshの際に使用するkeyを返却するメソッド
  • loadメソッド:LoadParamsからkeyを取得し、それをAPIのPageとして指定しデータを取得するメソッド

 getRefreshKeyは、refreshの際に使うkeyを返却するメソッドです。まずstateのclosestPageToPosition関数で指定したpositionのデータ取得することができます。データが取得できた場合は、loadメソッドで返却しているLoadResult.Pageが取得できるので、そのprevKeyとnextKeyから現在のKeyを算出して返却しています。また、指定したpositionのデータが見つからなかった場合はnullを返却します。

 loadメソッドは、LoadParamsからkeyを取得し、それをAPIのPageとして指定しデータを取得します。初期読み込みの場合などはkeyがnullで渡されるため、API側のpage指定の最小値でAPIの呼び出しを行います。

 APIでデータを取得できた場合LoadResult.Pageとしてデータと1つ前のkey、次のkeyを指定して返却します。エラーならLoadResult.Errorを返却します。

class AnimePagingSource(
    private val service: AnimeService,
) : PagingSource<Int, Anime>() {
    // APIのpage指定の最小値
    private val FIRST_INDEX = 0

    // APIの1チャンクあたりの取得データ数
    private val PAGE_SIZE = 30

    override fun getRefreshKey(state: PagingState<Int, Anime>): Int? {
        val position = state.anchorPosition ?: return null
        val prevKey = state.closestPageToPosition(position)?.prevKey
        val nextKey = state.closestPageToPosition(position)?.nextKey

        return prevKey?.plus(1) ?: nextKey?.minus(1)
    }

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Anime> {
        val position = params.key ?: FIRST_INDEX

        return try {
            withContext(Dispatchers.IO) {
                val result = service.getAnimes(
                    token = "取得したトークン", // APIの呼び出しに必要なため
                    page = position,
                    perPage = PAGE_SIZE,
                )

                val repositories = result.body()?.animeList
                val nextKey = if (repositories.isNullOrEmpty()) null else position + 1

                return@withContext LoadResult.Page(
                    data = repositories ?: listOf(),
                    prevKey = if (position >= FIRST_INDEX) position 1 else FIRST_INDEX,
                    nextKey = nextKey
                )
            }
        } catch (e: Exception) {
            return LoadResult.Error(e)
        }
    }
}

Repositoryの実装

 APIから取得したデータを表示するだけの場合は、Pagerの引数に、共通部分の説明で実装したPagingConfigに加え、pagingSourceFactoryに作成したPagingSourceを指定します。

 この際の注意点として、pagingSourceFactoryの引数が() -> PagingSource<Key, Value>となっているため、下記のコードで渡している形式ではなく、PagingSourceのインスタンスを渡すだけといった場合ではエラーになるので気を付けてください。

class AnimeRepository @Inject constructor(
    private val api: AnimeApi,
    private val service: AnimeService,
) {
    fun getAnimes(): Pager<Int, Anime> =
        Pager(
            config = PagingConfig(
                pageSize = 20,
                prefetchDistance = 60,
                enablePlaceholders = false,
            ),
            pagingSourceFactory = {
                AnimePagingSource(
                    service = service
                )
            },
        )
}

 Repository以降のFragmentやAdapterは共通の実装の部分と同じですので、ここまで実装するとAPIから取得したデータを表示するだけの場合の実装ができます。

 ここまで実装したところで、実行して表示を確認してみましょう。

APIから取得したデータを表示する
APIから取得したデータを表示する

 上記のように、APIから取得したデータをRecyclerViewでリスト表示できています。そしてスクロールすることでページング処理を行えていることが確認できます。 都合上サンプルアプリと異なり上記の画面キャプチャではサムネイルは非表示にしています。

次のページ
APIから取得したデータをDBに保存してキャッシュをする場合

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
アプリケーション開発の最新トレンド連載記事一覧

もっと読む

この記事の著者

長濱 伶(ヤフー株式会社)(ナガハマ レイ)

 2000年沖縄県生まれ。 学生時代に計算機シミュレーションを用いた文化の安定性に関する研究に従事。 2021年3月に沖縄工業高等専門学校のメディア情報工学科卒業後、4月にヤフー株式会社に入社。 2021年7月からPayPayフリマのAndroidアプリ開発に携わる。 Twitter: @Fel1Tech

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/15314 2022/02/17 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング