-
Notifications
You must be signed in to change notification settings - Fork 271
Closed
Description
Hello!
I use library version 3.0.0-alpha01
I'm trying to implement a multi-page search using pages. However, I faced an issue that it's not possible to replace data while the previous set is processing. And it looks like there is no way to stop processing or receive callback that processing has finished
So basically my Fragment observes data from ViewModel:
lifecycleScope.launch {
@OptIn(ExperimentalCoroutinesApi::class)
viewModel.searchData.distinctUntilChanged().collectLatest {
adapter?.submitData(it)
}
}
ViewModel triggers repository:
@ExperimentalCoroutinesApi
val searchData = searchRequest.asFlow().flatMapLatest {
val selectedStatuses = selectedStatuses.value?.toList() ?: emptyList()
val search = _search.value.orEmpty()
if (search.isNotBlank() || selectedStatuses.isNotEmpty()) {
repository.search(search, selectedStatuses.value?.toList() ?: emptyList()) { statuses, total, page ->
// some converting data stuff
}
} else {
flow { emit(PagingData.empty<SearchRecyclerModel>()) }
}
}
Repository:
val pagingSource = SearchPagingSource(appDatabase, databaseDataSource, remoteDataSource, dateHelper)
fun search(search: String, statuses: List<Long>, convertToRecyclerItems: (List<Result>, Int, Int) -> List<SearchRecyclerModel>) =
Pager(
PagingConfig(PAGE_SIZE),
initialKey = SearchData(search, statuses, 0, PAGE_SIZE)
) { pagingSource.setConverter(convertToRecyclerItems) }.flow
And SearchPagingSource
class SearchPagingSource(
private val appDatabase: AppDatabase,
private val databaseDataSource: DatabaseDataSource,
private val remoteDataSource: RemoteDataSource,
private val dateHelper: DateHelper
) :
PagingSource<SearchData, SearchRecyclerModel>() {
private val dateFormat = dateHelper.serverResponseDateFormat
private var convertToRecyclerItems: ((List<Result>, Int, Int) -> List<SearchRecyclerModel>)? = null
override suspend fun load(params: LoadParams<SearchData>): LoadResult<SearchData, SearchRecyclerModel> {
return try {
val key = params.key!!
val previousKey = if (key.offset == 0) null else key.copy(offset = key.offset - 1)
var nextKey: SearchData? = null
var total: Int
// internet request
// TODO why is it UI thread?
val result = remoteDataSource.search(key.criteria, key.statusIds, key.offset, key.limit)
// Here is response parsing
// ...
//
total = result?.data?.total ?: 0
nextKey = if (total < key.limit * (key.offset + 1)) null else key.copy(offset = key.offset + 1)
LoadResult.Page(
data = convertToRecyclerItems?.invoke(result, total, key.offset) ?: emptyList(),
prevKey = previousKey,
nextKey = nextKey
)
} catch (e: IOException) {
LoadResult.Error(e)
} catch (e: HttpException) {
LoadResult.Error(e)
}
}
// Convert server response into recycler's items
fun setConverter(convertToRecyclerItems: (List<Result>, Int, Int) -> List<SearchRecyclerModel>): SearchPagingSource {
this.convertToRecyclerItems = convertToRecyclerItems
return this
}
}
data class SearchData(val criteria: String, val statusIds: List<Long>, val offset: Int, val limit: Int)
Is there a way to handle it somehow?
Metadata
Metadata
Assignees
Labels
No labels