간편한 Paging3 붙여넣기

업무 중에 Paging3를 사용하면 현금인출 처리를 간단하게 적기 때문에 소개해 드리겠습니다.
공식.https://developer.android.com/topic/libraries/architecture/paging/v3-overview)

Retroffit 통신


@GET("/users/{user}/sample")
suspend fun samplePaging(params: String, page: Int): Response<Model>
여기는 별다른 일을 하지 않았습니다. 평소대로 쓰십시오.
리포지토리를 대체할 학급을 준비해야 하기 때문에 리포지토리가 필요 없다.

Paging Source(Repository 대체)


class SamplePagingSource(private val apiParams: String) : PagingSource<Int, String>(), KoinComponent {
    private val api: GithubService by inject()

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, String> {
        val page = params.key ?: 1
        val response = api.samplePaging(apiParams, page).datas

        return if (response != null) {
            LoadResult.Page(
                data = response,
                nextKey = page + 1, // 本当はAPIからの戻り値を元に次のページの有無確認など必要
                prevKey = page - 1
            )
        } else {
            LoadResult.Page(
                data = emptyList(),
                prevKey = null,
                nextKey = null
            )
        }
    }
}
API Get을 부르는 데 필요한 매개 변수는 작성기 매개 변수를 통해 전달됩니다.private val api: GithubService by inject() 부분적으로 Koin을 사용한 통신(서비스)
반에 다니고 있다.
상위 클래스에 대한 Paging Source 지정<ページングに使うキーの型, データの型>.
이번에는 페이지 정보를 숫자로 표시했기 때문에 Int, 데이터의 유형은 String이다
지정됨PagingSource<Int, String>.
API에서 데이터를 가져오는 작업을 마쳤을 때LoadResult.Page가 반환됩니다.LoadResult.Page.data Paging Source에서 지정한 유형의 List를 제공합니다.LoadResult.Page.prevKey 이전 페이지의 키LoadResult.Page.nextKey 다음 페이지의 키
를 클릭하고 를 클릭합니다.
※ (전면/하면) 페이지가 없을 때null을 제출합니다.
또 오류를 내고 싶으면 반납LoadResult.Error(e)할 수 있다.

ViewModel


    val samplePagingFlow: Flow<PagingData<String>> = Pager(
        PagingConfig(pageSize = 10, initialLoadSize = 10)
    ) {
        SamplePagingSource("params")
    }.flow.cachedIn(viewModelScope)
Paging Source를 Flow로 읽습니다.

Adapter


일반 ReyclearView어댑터와의 차이점은
  • DiffUtil.ItemCalleback
  • 필요
  • 항목을 가져오는 getItem 방법
    차이가 많지 않다.
  • Fragment


    class SampleAdapter : PagingDataAdapter<String, SampleAdapter.ViewHolder>(diffCallback) {
    
        override fun onBindViewHolder(holder: ViewHolder, position: Int) {
            holder.binding.title = getItem(position)
        }
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
            val binding = ViewSampleBinding.inflate(LayoutInflater.from(parent.context), parent, false)
            return ViewHolder(binding)
        }
    
        class ViewHolder(val binding: ViewSampleBinding) : RecyclerView.ViewHolder(binding.root)
    
        companion object {
            val diffCallback = object : DiffUtil.ItemCallback<String>() {
                override fun areItemsTheSame(oldItem: String, newItem: String): Boolean {
                    // 本当はユニークなidなどで比較する
                    return oldItem == newItem
                }
    
                override fun areContentsTheSame(oldItem: String, newItem: String): Boolean {
                    return oldItem == newItem
                }
            }
        }
    }
    
    ViewModel로 Flow화한 PagingSource가 변경되었을 때 Adapter#submitData를 진행한다.
    ※ 평소와 마찬가지로 RecyclearView.어댑터 및 LayoutManager를 지정하십시오.
    이렇게 하면 Paging 프로세스를 수행할 수 있습니다.

    추가(로드 중 진행 상태를 표시하려는 경우)


    Layout


    viewLifecycleOwner.lifecycleScope.launch {
        viewModel.samplePagingFlow.collectLatest { pagingData ->
            sampleAdapter.submitData(pagingData)
        }
    }
    
    진행률 막대만 설정할 레이아웃을 준비합니다.

    LoadStateAdapter


    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        xmlns:app="http://schemas.android.com/apk/res-auto">
        <ProgressBar
            android:id="@+id/progress"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    
    LoadState 어댑터 준비(RecyclearView.어댑터와 같은 내용)progress.visibility = if (loadState is LoadState.Loading) View.VISIBLE else View.GONE에서 진행 상태 표시/숨기기를 전환합니다.

    Fragment


    class SampleLoadStateAdapter : LoadStateAdapter<ViewHolder>() {
    
        override fun onBindViewHolder(holder: LoadStateViewHolder, loadState: LoadState) {
            val progress = holder.itemView.findViewById<ProgressBar>(R.id.progress)
            progress.visibility = if (loadState is LoadState.Loading) View.VISIBLE else View.GONE
        }
    
        override fun onCreateViewHolder(parent: ViewGroup, loadState: LoadState) =
            LoadStateViewHolder(parent)
    
        class ViewHolder(parent: ViewGroup) : RecyclerView.ViewHolder(
            LayoutInflater.from(parent.context)
                .inflate(R.layout.view_sample_load_state, parent, false)
        )
    }
    
    Fragment에서 withLoadState Footer만 지정하면 로드 여부를 판정할 수 있습니다.
    LoadState 어댑터가 지정한 로드에서 처리를 수행합니다.
    오류 시 다시 시도할 수 있으며 공식 샘플 앱도 소개되어 있습니다.
    ※ 집필할 때 보고 싶으면 404...

    좋은 웹페이지 즐겨찾기