Parth Makadia
Parth Makadia

Reputation: 341

How to show empty view while using Android Paging 3 library

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

Answers (4)

Ronald
Ronald

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

Amin Keshavarzian
Amin Keshavarzian

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

veeyikpong
veeyikpong

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

Gulzar Bhat
Gulzar Bhat

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

Related Questions