[Paging] UI에 로드 상태

페이징 라이브러리가 UI에 표시하기 위해 더 많은 항목을 가져올 때 더 많은 데이터를 가져오고 있음을 사용자에게 알리는 것이 좋습니다.

페이징 라이브러리는 CombinedLoadState 유형을 사용하여 로드 상태에 쉽게 액세스할 수 있는 방법을 제공합니다.

CombinedLoadState 인스턴스는 페이징 라이브러리에서 데이터를 로드하는 모든 구성 요소의 로드 상태를 설명합니다.

ArticlePagingSource의 LoadState에만 관심이 있으므로 주로 CombinedLoadState.source 필드의 LoadStates 유형을 사용합니다.

PagingDataAdapter 및 PagingDataAdapter.loadStateFlow를 통해 CombinedLoadStates에 액세스할 수 있습니다.

※ 로드 상태를 설명하는 데 도움이 되는 세 가지 클래스는 CombinedLoadStates, LoadStates 및 LoadState입니다.

CombinedLoadState에는 LoadStates 인스턴스가 있고 LoadStates는 LoadState 인스턴스를 제공합니다.

CombinedLoadStates.source는 LoadStates 유형이며 세 가지 유형의 LoadState 필드가 있습니다.

  • LoadStates.append: 사용자의 현재 위치에서 검색할 항목의 LoadState용
  • LoadStates.prepend: 사용자의 현재 위치 이전에 검색된 항목의 LoadState용
  • LoadStates.refresh: 초기 로드 시 LoadState용

각 LoadState 자체는 다음 중 하나일 수 있습니다.

  • LoadState.Loading: 항목 로드 중
  • LoadState.NotLoading: 기사가 로드되지 않았습니다.

  • LoadState.Error: 로드 오류가 발생했습니다.

여기서 중요한 점은 LoadState가 LoadState.Loading이라는 것입니다.

이는 ArticlePagingSource에 오류 사례가 포함되어 있지 않기 때문입니다.

먼저 UI의 상단과 하단에 진행률 표시줄을 추가하여 가져오기의 로드 상태를 양방향으로 표시합니다.

activity_articles.xml에서 다음과 같이 두 개의 LinearProgressIndicator 막대를 추가합니다.

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.ArticleActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/list"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:scrollbars="vertical"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.google.android.material.progressindicator.LinearProgressIndicator
        android:id="@+id/prepend_progress"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:indeterminate="true"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.google.android.material.progressindicator.LinearProgressIndicator
        android:id="@+id/append_progress"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:indeterminate="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

이제 PagingDataAdapter에서 LoadStatesFlow를 수집하고 CombinedLoadState에 반응합니다.

ArticleActivity.kt의 상태를 수집합니다.

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...

        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                articleAdapter.loadStateFlow.collect {
                    binding.prependProgress.isVisible = it.source.prepend is Loading
                    binding.appendProgress.isVisible = it.source.append is Loading
                }
            }
        }
        lifecycleScope.launch {
        ...
    }

마지막으로 ArticlePagingSource에 지연을 추가하여 로드합니다.

private const val LOAD_DELAY_MILLIS = 3_000L

class ArticlePagingSource : PagingSource<Int, Article>() {

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Article> {
        val start = params.key ?: STARTING_KEY
        val range = startKey.until(startKey + params.loadSize)

        if (start !
= STARTING_KEY) delay(LOAD_DELAY_MILLIS)         return ... }

지금까지 다룬 내용을 간략히 요약하면 다음과 같습니다.

  • 페이지 매김과 페이지 매김이 필요한 이유에 대해 간단히 살펴봅니다.

  • 호출기를 만들고 PagingSource를 정의하고 PagingData를 내보내 앱에 페이지 매김을 추가합니다.

  • cachedIn 연산자를 사용하여 ViewModel의 캐시 PagingData
  • PagingDataAdapter와 함께 UI에서 PagingData 사용
  • PagingDataAdapter.loadStateFlow를 사용하여 CombinedLoadStates로 돌아가기