Monday 8 March 2021

How to use Android androidx.paging.PagingDataAdapter loadStateFlow to show Empty, Loading and Loaded UI states

My current android application uses Room Paging3 library

implementation 'androidx.paging:paging-runtime-ktx:3.0.0-beta01'

My requirements are to display either a "Data Loading Spinner", an Empty message when no data is available, or the loaded data.

I can successfully show a loading spinner or the data when loaded, however when there's no data to display it does not work.

I've tried the solutions offered on SO, however none of them resolve my issue

The version of my code that successfully handles Loading and Loaded data resembles this:-

viewLifecycleOwner.lifecycleScope.launch {
            adapter.loadStateFlow
                .distinctUntilChangedBy { it.refresh }
                .filter { it.refresh is LoadState.NotLoading }
                .flowOn(Dispatchers.Default)
                .collectLatest {
                    withContext(Dispatchers.Main) {
                        if (adapter.itemCount == 0) (viewModel as HomeViewModel).loading.value = View.VISIBLE
                        else (viewModel as HomeViewModel).loading.value = View.GONE
                    }
                }
        }

I've tried to also show the empty state using this voted for SO answer, however it does not work for me

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
            }
        }

The issue is caused by the loadStateFlow emitting this condition

(loadState.source.refresh is LoadState.NotLoading && loadState.append.endOfPaginationReached && adapter.itemCount < 1)

while data is being loaded.

My list screen has pull to refresh, during the data refresh process I first delete all existing rows, then fetch all data remotely.

Is there anyway I can use PagingDataAdapter.loadStateFlow to show my three states of Loading, Loaded or Empty?

My ViewModel code resembles this:-

repository.myData()
          .map { pagingData ->
                 pagingData.map { myDO -> myDO.mapUI() }
               }
           .cachedIn(viewModelScope)
           .collect {
                emit(it)
                    }

My Repository code resembles this:-

fun myData(): Flow<PagingData<MyDO>> {
        return Pager(
            PagingConfig(pageSize = 60, prefetchDistance = 30, enablePlaceholders = false, maxSize = 200)
        ) {
            database.myDAO().fetchMyData()
        }.flow.flowOn(Dispatchers.IO)
    }

My Room query resembles this

@Query("SELECT * from my_table ORDER BY position_date DESC")
fun fetchMyData(): PagingSource<Int, MyDO>

Where have I gone wrong?

Is it possible to achieve my desired functionality?



from How to use Android androidx.paging.PagingDataAdapter loadStateFlow to show Empty, Loading and Loaded UI states

No comments:

Post a Comment