How to check the list size or for empty list in Paging 3 library

8.5k views Asked by At

I've been able to successfully implement the new alpha07 version of Paging 3 library by following the instructions available here: https://developer.android.com/topic/libraries/architecture/paging/v3-paged-data#guava-livedata

However, now I am in need of checking whether the returned list is empty or not in order to show a view or a text to the user, but I am not able to attach any checks in the flow structure of their paging design.

Currently this is how I have my code in Java in my onViewCreated after following their guides:

        MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class);

        LifecycleOwner lifecycleOwner = getViewLifecycleOwner();
        Lifecycle lifecycle = lifecycleOwner.getLifecycle();
        Pager<Integer, MyEntity> pager = new Pager<>(new PagingConfig(10), () -> viewModel.getMyPagingSource());
        LiveData<PagingData<MyEntity>> pagingDataLiveData = PagingLiveData.cachedIn(PagingLiveData.getLiveData(pager), lifecycle);

        pagingDataLiveData.observe(lifecycleOwner, data -> adapter.submitData(lifecycle, data));

I tried attaching a .filter on my data in the adapter.submitData(lifecycle, data), but it never receives null items despite the list being empty.

How can I check when the data submitted to the adapter is empty in this scenario? I couldn't find any pointers in their documentation.

EDIT: This is the solution I found, posting here because the selected answer is not strictly speaking the solution nor is it in java, but is the one that lead me to it.

I had to attach a LoadStateListener to my adapter, listen for when the LoadType is REFRESH and the LoadState is NotLoading, then check if the adapter.getItemCount is 0.

It's possible a different LoadType is more appropriate for this scenario, but the refresh is working so far for me so I went with that one.

Sample example:

// somewhere when you initialize your adapter
...
myAdapter.addLoadStateListener(this::loadStateListener);
...
private Unit loadStateListener(@Nonnull CombinedLoadStates combinedLoadStates) {

    if (!(combinedLoadStates.getRefresh() instanceof LoadState.NotLoading)) {
        return Unit.INSTANCE; // this is the void equivalent in kotlin
    }

    myView.setVisibility(adapter.getItemCount() == 0 ? View.VISIBLE : View.INVISIBLE);

    return Unit.INSTANCE; // this is the void equivalent in kotlin

}

NOTE: We have to return Unit.INSTANCE because that listener is in kotlin and that code is being used in java, returning this is the equivalent of not returning anything in java (void).

2

There are 2 answers

5
dlam On BEST ANSWER

The PagingData operators operate on individual items, so they won't get triggered if the page is empty.

Instead you want to check PagingDataAdapter.itemCount after the page has loaded, by observing loadStateFlow.

loadStateFlow.map { it.refresh }
    .distinctUntilChanged()
    .collect {
        if (it is NotLoading) {
            // PagingDataAdapter.itemCount here
        }
    }

Btw, null is a special value in Paging that denotes a placeholder, so you should not give Paging pages containing nulls, this is why the lower bound for the Value generic is non-null Any rather than Any?

1
deviant On

Unfortunately accepted answer didn't work well for my case. So instead of checking adapter's itemCount I throw custom exception (lets call it EmptyListException) when api returns empty list (by design it shouldn't). In my PagingSource.load() method i check if fetched data is empty:

return if (pagedResponse.page.isEmpty()){
    LoadResult.Error(EmptyListException())
} else {
    LoadResult.Page(pagedResponse.page, prevKey, nextKey)
}

Then i process result in the adapter.loadStateFlow.