Android/Paging3

[Android] Paging3, 스크롤 시 로딩 화면 추가하기

O_Gyong 2023. 1. 18.
 

[Android] Paging3 + Room + Flow 사용하기

[Android] RecyclerView에서 페이징+삭제 처리하기 #2 (with Room) [Android] RecyclerView에서 페이징 처리하기 #1 RecyclerView에서 리스트를 스크롤하다가 어느 순간에 로딩 화면이 뜨면서 리스트가 늘어나는 것을

ogyong.tistory.com

저번에 Paging3를 이용해서 리스트를 그려봤다.

여기에 추가로 스크롤을 해서 다음 페이지를 호출할 때 로딩 화면을 그려보려고 한다.

 

Paging3 라이브러리는 LoadState 클래스를 통해 데이터의 로드 상태를 추적할 수 있다.

그리고 로드 상태가 변경되면 LoadState 값을 자동으로 알림 받는 LoadStateAdapter가 존재한다.

 

해당 글은 Android Paging Advanced codelab을 참고했다.


 

로딩 레이아웃 만들기

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="8dp">
    <ProgressBar
        android:id="@+id/pb_loading"
        style="?android:attr/progressBarStyle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"/>
</LinearLayout>

로딩 화면을 표시하기 위해 list_item_footer.xml을 만들었다.

로딩 화면에는 ProgresBar만 보이게 했다.


LoadStateAdapter 만들기

/**
 * Paging3 라이브러리에서 제공하는 로드 상태를 표시하는 용도의 Adapter`
 * - 로드 상태가 변경되면 LoadState 값을 자동으로 알림을 받음
 */
class SampleLoadStateAdapter : LoadStateAdapter<SampleLoadStateAdapter.SampleLoadStateViewHolder>() {

    /**
     * LoadState 값을 받아 로딩 상태에 따라 ProgressBar의 visible 설정 처리
     */
    inner class SampleLoadStateViewHolder(
        private val binding: ListItemFooterBinding
    ) : RecyclerView.ViewHolder(binding.root) {

        fun bind(loadState: LoadState) {
            binding.pbLoading.isVisible = loadState is LoadState.Loading
        }
    }

    override fun onBindViewHolder(holder: SampleLoadStateViewHolder, loadState: LoadState) {
        holder.bind(loadState)
    }

    override fun onCreateViewHolder(parent: ViewGroup, loadState: LoadState): SampleLoadStateViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.list_item_footer, parent, false)
        val binding = ListItemFooterBinding.bind(view)
        return SampleLoadStateViewHolder(binding)
    }
}

LoadStateAdapter를 상속받는 SampleLoadStateAdapter.kt 파일을 만들었다.

LoadStateAdapter는 로드 상태가 변경되면 LoadState 값을 자동으로 받게 되고, 이 값을 ViewHolder에 넘겨준다.

bind 메서드에서 LoadState.Loading 값에 따라서 ProgresBar의 visible을 처리한다.

Codelab에서는 LoadStateViewHolder를 Adapter와 분리해놨는데,
로딩 기능만 구현하는데 분리할 필요를 못느껴서 Adapter에 inner class로 선언했다.

PagingDataAdapter와 LoadStateAdapter 연결

 // PagingDataAdapter에 LoadStateAdapter를 연결하여 로딩 view 추가
mBinding.rvMain.adapter = mAdapter.withLoadStateFooter(
     footer = SampleLoadStateAdapter()
 )

Activity에서 RecyclerView와 PagingDataAdapter를 연결할 때

withLoadState··· 메서드를 사용하면 LoadStateAdapter를 연결할 수 있다.

 

나는 footer 항목만 사용할 예정이기 때문에 withLoadStateFooter를 사용했다.


override suspend fun load(params: LoadParams<Int>): LoadResult<Int, SampleData> {
    ...
    delay(2000)
    return try {
        ...
}

테스트를 위해 SamplePagingSource 클래스에서 2초의 딜레이를 줬다.


 

전체 코드

댓글