10

I want to show empty view when paging3 is loaded with an empty list.

It seems to work with following code. Is this the proper way to do with the paging 3 library?:

        adapter?.addLoadStateListener { loadState ->
            adapter?.apply {
                if (itemCount <= 0 && !loadState.source.refresh.endOfPaginationReached) {
                    Timber.d("==> to show empty view")
                    tvEmptyView.isGone = false
                } else {
                    Timber.d("==> to hide empty view")
                    tvEmptyView.isGone = true
                }
            }
        } 
Eric Cen
  • 3,616
  • 1
  • 13
  • 17

3 Answers3

9

This worked for me:

if (loadState.source.refresh is LoadState.NotLoading &&
    loadState.append.endOfPaginationReached &&
    adapter.itemCount < 1
) {
   recyclerView.isVisible = false
   textViewEmpty.isVisible = true
} else {
    textViewEmpty.isVisible = false
}
Florian Walther
  • 6,237
  • 5
  • 46
  • 104
  • Your solution is just like mine; but since Paul posted his solution first, I marked his as the solution. thanks. – Eric Cen Dec 16 '20 at 17:08
5

You can directly plug into the adapter loadStateFlow, e.g

    lifecycleScope.launchWhenCreated {
        @OptIn(ExperimentalCoroutinesApi::class)
        adapter.loadStateFlow.collectLatest { loadStates ->
            val refresher = loadStates.refresh
            val displayEmptyMessage =  (refresher is LoadState.NotLoading && refresher.endOfPaginationReached && adapter.itemCount == 0)
            layoutBinding.emptyStateMessage.isVisible = displayEmptyMessage
            layoutBinding.emptyStateImage.isVisible = displayEmptyMessage
            layoutBinding.swipeToRefresh.isRefreshing = refresher is LoadState.Loading
        }
    }
Paul Okeke
  • 1,384
  • 1
  • 13
  • 19
  • 1
    For some reason `loadStates.refresh.endOfPaginationReached` not worked for me. I have to use `loadStates.append.endOfPaginationReached` (**`append`**) just like @Florian Walther answered. – Mahmudul Hasan Shohag Apr 19 '21 at 07:07
0

In my case I had to use a concatAdapter to display the empty view below the normal results if they are less than 11. Unfortunately paging 3 library will give me many false positive results regarding the LoadState.NotLoading and loadState.append.endOfPaginationReached States so I had to double check it by introducing a counter. Either Florian's or Paul's answer will work.

     offersAdapter.addLoadStateListener { updateUiOnNewLoadSate(it) }
    
     private fun updateUiOnNewLoadSate(loadState: CombinedLoadStates) {
    
            Timber.i("STATE $loadState")
          
            // Show empty view if results are less or equal 10
            val displayEmptySearch =
                loadState.source.refresh is LoadState.NotLoading && loadState.append.endOfPaginationReached && offersAdapter.itemCount <= 10 && loadStatesCounter > 1
            if (displayEmptySearch) {
    //here I display the empty view as a part of the
   //infinite scrolling recyclerview by using concatAdapter
                concatAdapter.addAdapter(emptyViewAdapter)
            } else {
                concatAdapter.removeAdapter(emptyViewAdapter)
            }
            loadStatesCounter++ //only apply above block when loadStatesCounter > 1
    }
ThanosFisherman
  • 5,626
  • 12
  • 38
  • 63
  • 1
    Try adding `adapter.itemCount < 1` to avoid a false positive before the data has loaded from the Flow – Florian Walther Mar 21 '21 at 17:51
  • Good catch Florian this also kinda worked but according to my logic I had to reverse the operator like this `adapter.itemCount > 1` This introduces another issue though. When there is a single result it won't display the empty view. So I'm keeping the counter for now. – ThanosFisherman Mar 24 '21 at 00:16