Android Jetpack Architecture/Paging3
PagingDataAdapter 정의하기.
hik14
2021. 8. 19. 15:43
PagingDataAdapter는 recyclerAdapter를 확장한다.
1. 데이터 로드 상태(LoadState)에 따른 Header/ Footer에 LoadStateAdapter 설정
2. LoadState를 알수 있는 Listener 제공
3. 아이템 항목을 다시 로드하는 기능 제공
4. 아이템 항목 구분자 설정
5. DiffUtil.ItemCallback을 지정을 통해 ListAdapter를 사용할때와 같이 사용할 수 있음.
private fun initAdapter() {
// 머릿목록 바닥목록 어뎁터 설정.
binding.list.adapter = adapter.withLoadStateHeaderAndFooter(
header = ReposLoadStateAdapter { adapter.retry() },
footer = ReposLoadStateAdapter { adapter.retry() },
)
// 로드 상태 리스너 설정
adapter.addLoadStateListener { loadState ->
// show empty list
val isListEmpty = loadState.refresh is LoadState.NotLoading && adapter.itemCount == 0
showEmptyList(isListEmpty)
// Only show the list if refresh succeeds.
binding.list.isVisible = loadState.mediator?.refresh is LoadState.NotLoading
// Show loading spinner during initial load or refresh.
binding.progressBar.isVisible = loadState.mediator?.refresh is LoadState.Loading
// Show the retry state if initial load or refresh fails.
binding.retryButton.isVisible = loadState.mediator?.refresh is LoadState.Error
// Toast on any error, regardless of whether it came from RemoteMediator or PagingSource
val errorState =
loadState.source.append as? LoadState.Error
?: loadState.source.prepend as? LoadState.Error
?: loadState.append as? LoadState.Error
?: loadState.prepend as? LoadState.Error
errorState?.let {
Toast.makeText(
this,
"\uD83D\uDE28 Wooops ${it.error}",
Toast.LENGTH_LONG
).show()
}
}
}
class ReposAdapter : PagingDataAdapter<UiModel, RecyclerView.ViewHolder>(UI_MODEL_COMPARATOR) {
companion object {
private val UI_MODEL_COMPARATOR = object : DiffUtil.ItemCallback<UiModel>() {
override fun areItemsTheSame(oldItem: UiModel, newItem: UiModel): Boolean =
(oldItem is UiModel.RepoItem && newItem is UiModel.RepoItem && oldItem.repo.fullName == newItem.repo.fullName)
|| (oldItem is UiModel.SeparatorItem && newItem is UiModel.SeparatorItem && oldItem.description == newItem.description)
override fun areContentsTheSame(oldItem: UiModel, newItem: UiModel): Boolean =
oldItem == newItem
}
}
override fun getItemViewType(position: Int): Int {
return when (getItem(position)) {
is UiModel.RepoItem -> R.layout.repo_view_item
is UiModel.SeparatorItem -> R.layout.separator_view_item
null -> throw UnsupportedOperationException("Unknown view")
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val uiModel = getItem(position)
uiModel.let {
when (uiModel) {
is UiModel.RepoItem -> (holder as RepoViewHolder).bind(uiModel.repo)
is UiModel.SeparatorItem -> (holder as SeparatorViewHolder).bind(uiModel.description)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
if (viewType == R.layout.repo_view_item) {
RepoViewHolder.create(parent)
} else {
SeparatorViewHolder.create(parent)
}
}