I'm trying to use the paging library for my project but it doesn't seem to work. I'll leave my classes below to see if anyone can help me.
My FrutasViewModel:
class FrutasViewModel : ViewModel() {
private lateinit var content: Flow<PagingData<CategoryProductQueryRequest>>
var stateStatus =
MutableStateFlow<StateStatus<Flow<PagingData<CategoryProductQueryRequest>>>>(StateStatus.Start)
val managedGrpc = ManagedGrpc()
private var stubCategoryProductQuery: CategoryProductQueryGrpc.CategoryProductQueryStub
init {
managedGrpc.inicializar("categoryproduct")
stubCategoryProductQuery = CategoryProductQueryGrpc.newStub(managedGrpc.canal)
}
fun openChannel() {
if (managedGrpc.canal.isShutdown) {
managedGrpc.inicializar("categoryproduct")
stubCategoryProductQuery = CategoryProductQueryGrpc.newStub(managedGrpc.canal)
}
}
fun getFrutas(id: Int?): Flow<PagingData<CategoryProductQueryRequest>> {
stateStatus.value = StateStatus.Loading
try {
content = getFrutasPage(id).cachedIn(viewModelScope)
stateStatus.value = StateStatus.Success(content)
} catch (e: Exception) {
stateStatus.value = StateStatus.Failure(errorMessage = e.localizedMessage!!)
}
return content
}
private fun getFrutasPage(id: Int?): Flow<PagingData<CategoryProductQueryRequest>> {
return Pager(
config = PagingConfig(
pageSize = 10,
enablePlaceholders = false
),
pagingSourceFactory = {
ShoppingDataSource(
id = id,
stub = stubCategoryProductQuery,
managedGrpc = managedGrpc
)
}
).flow
}
}
My ShoppingDataSource:
class ShoppingDataSource(
private val id:Int?,
private var stub: CategoryProductQueryGrpc.CategoryProductQueryStub,
private var managedGrpc : ManagedGrpc
) : PagingSource<Int, CategoryProductQueryRequest>() {
private var itens: CategoryQueryResponse? = null
private var requestObserver: StreamObserver<CategoryQueryRequest>?=null
private val responseObserver = object : StreamObserver<CategoryQueryResponse> {
override fun onNext(response: CategoryQueryResponse) {
itens =CategoryQueryResponse.newBuilder()
.setCount(response.count)
.setNextPage(response.nextPage)
.setPrevPage(response.prevPage)
.addAllResults(response.resultsList)
.setPages(response.pages).build()
}
override fun onError(t: Throwable?) {
val status: Status = Status.fromThrowable(t)
Log.e("Failed",status.description!!)
finishLatch.countDown()
}
override fun onCompleted() {
finishLatch.countDown()
}
}
val finishLatch = CountDownLatch(1)
// Função para fechar o canal gRPC
private fun closeCanal() {
if (!managedGrpc.canal.isShutdown) {
managedGrpc.canal.shutdown()
}
}
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, CategoryProductQueryRequest> {
// Retrofit calls that return the body type throw either IOException for network
// failures, or HttpException for any non-2xx HTTP status codes. This code reports all
// errors to the UI, but you can inspect/wrap the exceptions to provide more context.
return try {
// Key may be null during a refresh, if no explicit key is passed into Pager
// construction. Use 0 as default, because our API is indexed started at index 0
val pageNumber = params.key ?: 0
// Suspending network load via Retrofit. This doesn't need to be wrapped in a
// withContext(Dispatcher.IO) { ... } block since Retrofit's Coroutine
// CallAdapter dispatches on a worker thread.
requestObserver =stub.getCategoryProduct(responseObserver)
try {
val request= CategoryQueryRequest.newBuilder()
.setData(id!!.toLong())
.setPageNum(pageNumber)
.build()
requestObserver?.onNext(request)
withContext(Dispatchers.IO) {
finishLatch.await(1000, TimeUnit.MILLISECONDS)
}
} catch (e: RuntimeException) {
requestObserver?.onError(e)
Log.e("ERRO",e.message!!)
}
// Since 0 is the lowest page number, return null to signify no more pages should
// be loaded before it.
val prevKey = if (pageNumber > 1) pageNumber - 1 else null
// This API defines that it's out of data when a page returns empty. When out of
// data, we return `null` to signify no more pages should be loaded
val nextKey = if (pageNumber+1>itens!!.pages) null else pageNumber+1
if(nextKey==null){
requestObserver?.onCompleted()
closeCanal()
}
LoadResult.Page(
data = itens!!.resultsList,
prevKey = prevKey,
nextKey = nextKey
)
} catch (e: IOException) {
closeCanal()
LoadResult.Error(e)
} catch (e: HttpException) {
if (Build.VERSION.SDK_INT >= 34) {
closeCanal()
LoadResult.Error(e)
} else {
closeCanal()
TODO("VERSION.SDK_INT < 34")
}
}
}
override fun getRefreshKey(state: PagingState<Int, CategoryProductQueryRequest>): Int? {
return state.anchorPosition?.let {
state.closestPageToPosition(it)?.prevKey?.plus(1)
?: state.closestPageToPosition(it)?.nextKey?.minus(1)
}
}
}
My class StateStatus:
sealed class StateStatus<out T> where T : Any? {
object Start : StateStatus<Nothing>()
object Loading : StateStatus<Nothing>()
data class Success<T>(val data: T) : StateStatus<T>()
data class Failure(val errorMessage: String) : StateStatus<Nothing>()
}
And finally my code calls the viewmodel:
LaunchedEffect(Unit){
withContext(Dispatchers.IO) {
// Operações de entrada/saída (ex: chamadas de rede) aqui
viewModel.getFrutas(id, without)
}
}
val states by viewModel.stateStatus.collectAsState()
when (states) {
is StateStatus.Start -> {
}
StateStatus.Loading -> {
helpers.LoadingComponent()
}
is StateStatus.Failure -> {
Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize()) {
Text(text = stringResource(id = R.string.error),fontSize = 16.sp)
}
}
is StateStatus.Success -> {
list = (states as StateStatus.Success).data.collectAsLazyPagingItems()
images = imgs
idFrutas = id
modelFrutas=viewModel
LazyColumn(
state = rememberLazyListState(),
) {
items(
count = list.itemCount,
key = list.itemKey(),
contentType = list.itemContentType()
)
{ index ->
val item = list[index]
if (item != null) {
var visible by rememberSaveable(index) {
mutableStateOf(true)
}
ShowCategories(item)
}
}
}
}
}
}
Version:
implementation("androidx.paging:paging-compose:3.2.1") implementation("androidx.paging:paging-runtime-ktx:3.2.1")
When I execute the project and see the list on my cell phone, it slows down, does anyone know how to help me fix it?