0Pricing
Android Academy · レッスン

Pagingが必要な理由

すべてのデータを一度に読み込むコストを学びます。

「Pagingが必要な理由」はCoddyKit上の無料Android Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAndroid Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Android Academyコースには全4レッスンが含まれています。

すべて読み込むとコストが高い

50,000件のアイテムがあるフィードを想像してください。すべてを一度に取得して保持すると、メモリを浪費し、ネットワークを遅くし、レスポンスの解析中にUIを停止させてしまいます。

ほとんどのユーザーがスクロールするのは、最初の数画面だけです。Pagingとは、最初にすべてを読み込むのではなく、ユーザーのスクロールに合わせてデータを小さなまとまり(ページ)単位で読み込むことです。

コードの問題点

単純な方法では、リスト全体をメモリに読み込みます。サーバーが対応していても、レスポンスが非常に大きくなる可能性があり、解析後のリストがヒープの大部分を占有します。

このパターンは大規模化に適さず、大きなデータセットではOutOfMemoryErrorが発生する危険があります。

// Anti-pattern: load the whole table at once
suspend fun loadAllArticles(): List<Article> {
    // Could be tens of thousands of rows / megabytes of JSON
    return api.getArticles(limit = 50_000)
}

// UI holds ALL of them in memory at once
val articles = loadAllArticles()
LazyColumn {
    items(articles) { article -> ArticleRow(article) }
}

ページの構造

ページとは、データセットを小さく分割したまとまりで、通常は20~50個の項目で構成されます。サーバーは1ページ分のデータと、次のページを示すポインター(番号、オフセット、トークンなど)を返します。

アプリはメモリに保持するページを数ページ分に限定し、ユーザーがスクロールして離れた古いページを破棄します。

data class ArticlePage(
    val items: List<Article>,
    val nextKey: Int?   // null means no more pages
)

// Example REST call returning one page
suspend fun getArticlePage(page: Int, size: Int = 20): ArticlePage

Paging 3 の概要

Paging 3は、ページングに必要な難しい処理をすべて代わりに行うJetpackライブラリです。

  • ユーザーがリストの末尾に近づいたときに次のページをリクエストする
  • メモリに保持する項目を一定の範囲に限定する
  • 読み込み状態とエラー状態を公開する
  • coroutines、Flow、Jetpack Composeを標準でサポートする

依存関係の追加

Paging 3は、ランタイムとCompose統合用の個別のアーティファクトとして提供されています。モジュールのbuild.gradle.ktsに追加してください。

paging-composeアーティファクトには、LazyColumn用のヘルパーが用意されています。

// build.gradle.kts (module)
dependencies {
    val pagingVersion = "3.3.6"
    implementation("androidx.paging:paging-runtime:$pagingVersion")
    implementation("androidx.paging:paging-compose:$pagingVersion")
}

3つの基本要素

Paging 3では、次の3つの型を繰り返し使用します。

  • PagingSource - データソースから1ページ分を読み込む方法を把握します
  • Pager - ページングされたデータのストリームを設定して生成します
  • PagingData - Flowとして発行される項目のコンテナです

次のレッスンで、これらを1つずつ構築します。

PagingData と Flow

リポジトリはFlow<PagingData<T>>を公開します。UIはこれを収集し、その時点で読み込まれている項目を表示します。

完全なリストを自分で組み立てる必要はありません。Pagingが必要に応じて項目をUIへストリーミングします。

import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import kotlinx.coroutines.flow.Flow

class ArticleRepository(private val api: ArticleApi) {
    fun articles(): Flow<PagingData<Article>> = Pager(
        config = PagingConfig(pageSize = 20)
    ) {
        ArticlePagingSource(api)
    }.flow
}

PagingConfig による範囲の制御

PagingConfigでは、Pagingによるデータの読み込み方法と保持方法を調整できます。

  • pageSize - 1回のページリクエストで取得する項目数
  • prefetchDistance - 次の読み込みを開始する、端からの距離
  • enablePlaceholders - まだ読み込まれていない項目のプレースホルダーを表示するかどうか
  • maxSize - メモリに保持する項目数の上限
import androidx.paging.PagingConfig

val config = PagingConfig(
    pageSize = 20,
    prefetchDistance = 5,
    enablePlaceholders = false,
    maxSize = 100
)

ネットワークかデータベースか、それとも両方か

PagingSourceは、REST API、Roomデータベース、その他のカスタムソースからデータを取得できます。

真のオフラインファースト体験を実現するには、RemoteMediator(最後のレッスンで扱います)を使って両方を組み合わせます。ネットワークからローカルデータベースにデータを格納し、UIはそのデータベースをページングします。

滑らかなスクロールとメモリ使用量の削減

ページングを使うと、各リクエストが小さく、メモリ上のウィンドウもmaxSizeによって制限されるため、スクロールが滑らかになります。

読み込みインジケーターやエラーインジケーターはLoadStateによって自動的に提供されます。そのため、手動で状態を管理しなくても、画面下部にスピナーや再試行ボタンを表示できます。

// LoadState exposes loading/error per direction
when (val state = adapterLoadState.append) {
    is LoadState.Loading -> showBottomSpinner()
    is LoadState.Error -> showRetry(state.error)
    is LoadState.NotLoading -> hideBottomSpinner()
}

Paging が必要な場合

次のような場合はPaging 3を使用してください。

  • データセットが大きい、または上限がない(フィード、検索結果、チャット履歴など)
  • ページまたはカーソルを返すネットワークAPIからデータを取得する
  • 読み込み・エラーUIの自動化とメモリ制御が必要である

短く固定されたリスト(設定メニューなど)であれば、通常のLazyColumnのほうがシンプルで、十分に適しています。

確認問題

大きなリストでPaging 3を使用する主なメリットは何ですか?

まとめ:Paging を使う理由

すべてのデータを一度に読み込むとパフォーマンスとメモリに悪影響がある理由と、Paging 3がそれをどのように解決するかを学びました。

  • ユーザーのスクロールに応じて、小さなページ単位でデータを読み込む
  • 3つの基本要素はPagingSource、Pager、PagingDataである
  • PagingConfigでページサイズ、先読み、メモリ上のウィンドウを調整できる
  • Pagingはcoroutines、Flow、Composeと統合でき、読み込み・エラー状態も自動的に提供する

次は、PagingSourceを構築してPagerに接続します。

よくある質問

「Pagingが必要な理由」レッスンは無料ですか?

はい。「Pagingが必要な理由」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Android Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Android Academyコースには全4レッスンが含まれています。

「Pagingが必要な理由」で何を学びますか?

すべてのデータを一度に読み込むコストを学びます。 ブラウザで直接実行するハンズオンコードでAndroid Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Android Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのAndroid Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「Pagingが必要な理由」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このAndroid Academyレッスンでコードを書いて実行できますか?

はい。すべてのAndroid Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Pagingが必要な理由
  2. PagingSourceとPager
  3. ComposeのリストでPagingを使う
  4. RemoteMediatorとキャッシュ
← Android Academyに戻る