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?
UPDATE
I believe that I have two separate issues.
The first is caused by my initial data sync, where I employ Android Workers to download data from a remote source and insert into my local Room database. Due to how the remote data is organised and the available Restful API's, the data displayed in a list can be inserted by multiple workers. This "partitioning" of the data inserted locally, results in the data submitted to my Paging3 adapter to be sporadic and means the Load State cycles through Loading -> Not Loading -> Loading -> Not Loading.
I display the list Fragment while the sync is on going, which results in the screen contents "Flashing" between the loading Spinner and the displayed data list