I'm using Paging3 library, and when I get data from the server, I'm importing it to PagingData via PagingSource.
It works well if no parameters are needed for API calls, like this:
class ProductPagingSource(
private val productApi: ProductApi,
) : PagingSource<Int, ProductEntity>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, ProductEntity> {
try {
val nextPageNumber = params.key ?: 1
val response = productApi.getProduct(nextPageNumber)
return if (response.isSuccessful) {
val data = response.body()?.data
val productList = data?.product ?: emptyList()
LoadResult.Page(
data = productList,
prevKey = if (nextPageNumber == 1) null else nextPageNumber - 1,
nextKey = if (eventList.isEmpty()) null else nextPageNumber + 1,
)
} else {
LoadResult.Error(Exception("Error loading data"))
}
} catch (e: Exception) {
Log.e("TAG", e.toString())
return LoadResult.Error(e)
}
}
}
@HiltViewModel
class ProductViewModel @Inject constructor(
getProductUseCase: GetProductUseCase,
) : BaseViewModel() {
private val _productList: StateFlow<PagingData<Product>> =
getProductUseCase.invoke()
.cachedIn(viewModelScope)
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), PagingData.empty())
val productList get() = _productList
but there is a problem that requires searching through multiple parameters.
I currently have to use three parameters. (Query String
, Category
, Product Division
)
Whether the search term changes or the category changes, the data must change with each change.
As a result of searching, it was found that using switchMap
runs the lambda function whenever LiveData
changes.
But since I'm using Flow
, I saw a document that flatMapLatest
is doing exactly the same thing in Flow, so I wrote the code as follows:
private val _division: MutableStateFlow<String> = MutableStateFlow("All")
private val _query: MutableStateFlow<String?> = MutableStateFlow(null)
private val _category: MutableStateFlow<Int?> = MutableStateFlow(null)
@OptIn(ExperimentalCoroutinesApi::class)
private val _productList: StateFlow<PagingData<Product>> =
_query.flatMapLatest { queryString ->
_category.flatMapLatest { categoryId ->
_division.flatMapLatest {
val productDivision = if (it == "All") null else it
getProductUseCase.invoke(queryString, categoryId, productDivision)
.cachedIn(viewModelScope)
}
}
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), PagingData.empty())
However, it only works when initialized (when all parameters are in the initial situation) and does not work whenever the parameters change.
What should I do in this situation?