Reputation: 341
I am using Paging 3 lib. and i am able to check if refresh state is "Loading" or "Error" but i am not sure how to check "empty" state.I am able to add following condition but i am not sure if its proper condition
adapter.loadStateFlow.collectLatest { loadStates ->
viewBinding.sflLoadingView.setVisibility(loadStates.refresh is LoadState.Loading)
viewBinding.llErrorView.setVisibility(loadStates.refresh is LoadState.Error)
viewBinding.button.setOnClickListener { pagingAdapter.refresh() }
if(loadStates.refresh is LoadState.NotLoading && (viewBinding.recyclerView.adapter as ConcatAdapter).itemCount == 0){
viewBinding.llEmptyView.setVisibility(true)
}else{
viewBinding.llEmptyView.setVisibility(false)
}
}
Also I am running into other problem I have implemented search functionality and until more than 2 characters are entered i am using same paging source like following but the above loadstate callback is executed only once.So thats why i am not able to hide empty view if search query is cleared.I am doing so to save api call from front end.
private val originalList : LiveData<PagingData<ModelResponse>> = Transformations.switchMap(liveData){
repository.fetchSearchResults("").cachedIn(viewModelScope)
}
val list : LiveData<LiveData<PagingData<ModelResponse>>> = Transformations.switchMap{ query ->
if(query != null) {
if (query.length >= 2)
repository.fetchSearchResults(query)
else
originalList
}else
liveData { emptyList<ModelResponse>() }
}
Upvotes: 24
Views: 17518
Reputation: 734
If you are using paging 3 with Jetpack compose, I had a similar situation where I wanted to show a "no results" screen with the Pager 3 library. I wasn't sure what the best approach was in Compose but I use now this extension function on LazyPagingItems
. It checks if there are no items and makes sure there are no items coming by checking if endOfPaginationReached
is true.
private val <T : Any> LazyPagingItems<T>.noItems
get() = loadState.append.endOfPaginationReached && itemCount == 0
Example usage is as follows:
@Composable
private fun ArticlesOverviewScreen(screenContent: Content) {
val lazyBoughtArticles = screenContent.articles.collectAsLazyPagingItems()
when {
lazyBoughtArticles.noItems -> NoArticlesScreen()
else -> ArticlesScreen(lazyBoughtArticles)
}
}
Clean and simple :).
Upvotes: 3
Reputation: 3943
adapter.loadStateFlow.collect {
if (it.append is LoadState.NotLoading && it.append.endOfPaginationReached) {
emptyState.isVisible = adapter.itemCount < 1
}
}
The logic is,If the append has finished (it.append is LoadState.NotLoading && it.append.endOfPaginationReached == true), and our adapter items count is zero (adapter.itemCount < 1), means there is nothing to show, so we show the empty state.
PS: for initial loading you can find out more at this answer: https://stackoverflow.com/a/67661269/2472350
Upvotes: 8
Reputation: 857
I am using this way and it works.
EDITED:
dataRefreshFlow
is deprecated in Version 3.0.0-alpha10, we should use loadStateFlow
now.
viewLifecycleOwner.lifecycleScope.launch {
transactionAdapter.loadStateFlow
.collectLatest {
if(it.refresh is LoadState.NotLoading){
binding.textNoTransaction.isVisible = transactionAdapter.itemCount<1
}
}
}
For detailed explanation and usage of loadStateFlow
, please check
https://developer.android.com/topic/libraries/architecture/paging/v3-paged-data#load-state-listener
Upvotes: 3
Reputation: 1355
Here is the proper way of handling the empty view in Android Paging 3:
adapter.addLoadStateListener { loadState ->
if (loadState.source.refresh is LoadState.NotLoading && loadState.append.endOfPaginationReached && adapter.itemCount < 1) {
recycleView?.isVisible = false
emptyView?.isVisible = true
} else {
recycleView?.isVisible = true
emptyView?.isVisible = false
}
}
Upvotes: 68