0Pricing
Android Academy · レッスン

ComposeのリストでPagingを使う

LazyColumnでページングされたデータを描画します。

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

Compose でページングされたデータを表示する

データレイヤーからFlow<PagingData<Article>>が渡されます。paging-composeライブラリは、このFlowをLazyColumnで表示できる形式に変換します。ユーザーのスクロールに応じたオンデマンド読み込みにも対応しています。

その橋渡しを担うのがcollectAsLazyPagingItems()です。

collectAsLazyPagingItems

コンポーザブル内で、Flowに対してcollectAsLazyPagingItems()を呼び出します。読み込まれた項目と読み込み状態を追跡するLazyPagingItemsオブジェクトが返され、ページが到着するたびにUIが再コンポーズされます。

import androidx.paging.compose.collectAsLazyPagingItems

@Composable
fun ArticleScreen(viewModel: ArticleViewModel) {
    val articles = viewModel.articles.collectAsLazyPagingItems()
    ArticleList(articles)
}

LazyPagingItems で items() を使う

LazyColumn内では、Pagingのitems()オーバーロードを使用します。これはLazyPagingItemsから項目を読み取り、ユーザーが末尾に近づくと次のページの読み込みを開始します。

プレースホルダーが有効な場合、項目がnullになることがあるため、そのケースを処理してください。

import androidx.compose.foundation.lazy.LazyColumn
import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.items

@Composable
fun ArticleList(articles: LazyPagingItems<Article>) {
    LazyColumn {
        items(articles) { article ->
            if (article != null) {
                ArticleRow(article)
            }
        }
    }
}

項目の安定したキー

各行に安定したキーを指定すると、Composeがページの読み込みをまたいで項目を効率的に追跡でき、不要な再コンポーズを防げます。

項目IDのような一意で安定したプロパティとともに、PagingのitemKeyヘルパーを使用してください。

import androidx.paging.compose.itemKey

LazyColumn {
    items(
        count = articles.itemCount,
        key = articles.itemKey { it.id }
    ) { index ->
        val article = articles[index]
        if (article != null) ArticleRow(article)
    }
}

読み込み状態の確認

LazyPagingItems.loadStateは、次の3つの操作について現在の読み込み状態とエラー状態を公開します。

  • refresh - 初回読み込みまたはプル・トゥ・リフレッシュ
  • append - 次のページの読み込み(下方向へのスクロール)
  • prepend - 前のページの読み込み(上方向へのスクロール)
import androidx.paging.LoadState

val refresh = articles.loadState.refresh
val append = articles.loadState.append

val isInitialLoading = refresh is LoadState.Loading
val isLoadingMore = append is LoadState.Loading

全画面の読み込み状態と空状態

refresh状態を使って、画面を開いたときの表示を制御します。読み込み中は中央にスピナーを表示し、失敗時はエラー画面を表示し、表示する項目がない場合は空であることを示すメッセージを表示します。

when (val refresh = articles.loadState.refresh) {
    is LoadState.Loading -> FullScreenSpinner()
    is LoadState.Error -> FullScreenError(
        message = refresh.error.message,
        onRetry = { articles.retry() }
    )
    is LoadState.NotLoading -> {
        if (articles.itemCount == 0) EmptyState()
        else ArticleList(articles)
    }
}

追加読み込み中のフッタースピナー

次のページの読み込み中に画面下部へ小さなスピナーを表示するには、appendの読み込み状態に応じてLazyColumnに追加の項目を挿入します。

LazyColumn {
    items(count = articles.itemCount, key = articles.itemKey { it.id }) { index ->
        articles[index]?.let { ArticleRow(it) }
    }

    if (articles.loadState.append is LoadState.Loading) {
        item {
            Box(Modifier.fillMaxWidth().padding(16.dp), Alignment.Center) {
                CircularProgressIndicator()
            }
        }
    }
}

エラー時の再試行

追加読み込みに失敗した場合は、画面下部に再試行用の行を表示します。articles.retry()を呼び出すと、失敗した読み込みだけを再試行し、リスト全体を再読み込みすることはありません。

val append = articles.loadState.append
if (append is LoadState.Error) {
    item {
        Row(Modifier.fillMaxWidth().padding(16.dp), Arrangement.Center) {
            Text("Couldn't load more")
            Spacer(Modifier.width(8.dp))
            Button(onClick = { articles.retry() }) { Text("Retry") }
        }
    }
}

プル・トゥ・リフレッシュ

articles.refresh()で新しい読み込みを開始します。これをMaterial 3のプル・トゥ・リフレッシュと組み合わせ、refreshの読み込み状態からインジケーターを制御します。

import androidx.compose.material3.pulltorefresh.PullToRefreshBox

val isRefreshing = articles.loadState.refresh is LoadState.Loading
PullToRefreshBox(
    isRefreshing = isRefreshing,
    onRefresh = { articles.refresh() }
) {
    ArticleList(articles)
}

ヘッダーと区切り線

同じLazyColumn内で、ページングされた項目とページングされていないコンテンツを自由に組み合わせられます。ページングされたitems()の前後に、固定ヘッダー、検索バー、セクション区切りなどを追加できます。

すべてが1つのLazyColumnに含まれるため、スクロールは一貫して滑らかに保たれます。

LazyColumn {
    item { SearchBar(query, onQueryChange) }

    items(count = articles.itemCount, key = articles.itemKey { it.id }) { index ->
        val article = articles[index]
        if (article != null) {
            ArticleRow(article)
            HorizontalDivider()
        }
    }

    if (articles.loadState.append.endOfPaginationReached) {
        item { Text("You're all caught up", Modifier.padding(16.dp)) }
    }
}

ページングされたリストのプレビュー

Composeのプレビューやテストに、実際のネットワークは必要ありません。サンプルデータをPagingData.from(...)でラップし、Flowとして公開します。

これにより、リストUIを他の処理から分離して構築・プレビューできます。

import androidx.paging.PagingData
import kotlinx.coroutines.flow.flowOf

@Preview
@Composable
fun ArticleListPreview() {
    val sample = listOf(Article(1, "Hello"), Article(2, "World"))
    val flow = flowOf(PagingData.from(sample))
    ArticleList(flow.collectAsLazyPagingItems())
}

確認問題

Flow<PagingData>を、ComposeのLazyColumnで表示できる形式に変換する関数はどれですか?

まとめ:Compose での Paging

Jetpack Composeでページングされたデータを表示しました。

  • collectAsLazyPagingItems()がFlowとUIを橋渡しする
  • Pagingのitems()オーバーロードはスクロールに応じて追加データを読み込む。nullのプレースホルダーを処理する
  • 安定したキーにはitemKey { it.id }を使用する
  • loadState.refresh/append/prependでスピナー、エラー、空状態を制御する
  • retry()とrefresh()で失敗から復旧し、再読み込みする

次は、RemoteMediatorを使ってネットワークとデータベースを組み合わせます。

よくある質問

「ComposeのリストでPagingを使う」レッスンは無料ですか?

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

「ComposeのリストでPagingを使う」で何を学びますか?

LazyColumnでページングされたデータを描画します。 ブラウザで直接実行するハンズオンコードでAndroid Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

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

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

「ComposeのリストでPagingを使う」レッスンにはどのくらい時間がかかりますか?

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

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

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

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

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