Hi there! I noticed a weird behaviour and after in...
# compose
m
Hi there! I noticed a weird behaviour and after investigating many hours I cannot understand what is happening. Basically, I’m developing an app that requires pagination. The layout was developed in Jetpack Compose and the pagination using
RemoteMediator
. However, when I render the screen I noticed that instead of fetch the first page from the server, it will be fetched more 3 pages from the server. So, for example, if my page size is 20, after I render the screen, I’ll fetch 80 elements from the server. I cannot understand why this is happening. I’ll leave here the relevant code that I’m using to do that. If anyone have an ideia about what is happening, please let me know. Thank you in advance! 🙏
Copy code
@OptIn(ExperimentalPagingApi::class)
class Mediator(
    private val getMessages: suspend (String?) -> ChatResponse,
    private val remoteKeyDao: RemoteKeyDao,
    private val handleHttpException: (Context, HttpException) -> Unit,
) : RemoteMediator<Int, ChatMessage>() {

    override suspend fun load(
        loadType: LoadType,
        state: PagingState<Int, ChatMessage>
    ): MediatorResult {
        return try {
            val loadKey = when (loadType) {
                LoadType.REFRESH -> null
                LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
                LoadType.APPEND -> remoteKeyDao.getRemoteKey(query)?.token
            }
            val response = getMessages(loadKey)
            if (loadType == LoadType.REFRESH) remoteKeyDao.deleteByQuery(query)
            remoteKeyDao.insertOrReplace(RemoteKey(query, response.pagination.token))
            // ...
            MediatorResult.Success(endOfPaginationReached = response.chats.isEmpty())
        } catch (e: IOException) {
            MediatorResult.Error(e)
        } catch (e: HttpException) {
            handleHttpException(context, e)
            MediatorResult.Error(e)
        }
    }
}

//ViewModel
@HiltViewModel
class ChatViewModel
@Inject constructor(
) : ViewModel() {

    private val _state = MutableStateFlow(State())
    val state = _state.asStateFlow()
    private val _effect = MutableSharedFlow<Effect>()
    val effect = _effect.asSharedFlow()

    var chats: Flow<PagingData<ChatMessage>>? = null

    data class State(
        val isChatInitialized: Boolean = false
    )

    fun onStart() {
        getChats()
    }
   
   @OptIn(ExperimentalPagingApi::class)
    private fun getChats() {
        val pager = Pager(
            config = PagingConfig(pageSize = 20),
            remoteMediator = ChatMediator(
                { chatUseCase.getChats(it) },
                remoteKeyDao,
                ::handleHandleHttpException
            )
        ) { messagesDao.pagingSource() }
        chats = pager.flow.cachedIn(viewModelScope)
        _state.value = _state.value.copy(isChatInitialized = true)
    }
}

// Jetpack Compose
@OptIn(ExperimentalMaterialApi::class, ExperimentalCoroutinesApi::class)
@Composable
fun ChatView(
    viewModel: ChatViewModel,
    navController: NavController
) {
    val viewState by viewModel.state.collectAsStateLifecycleAware()

    LaunchedEffect(viewModel) {
        viewModel.onStart()
    }

    Scaffold(
        scaffoldState = state,
        floatingActionButton = fab
    ) { innerPadding ->
        Box(modifier = Modifier.padding(innerPadding)) {
            if (viewState.isChatInitialized) {
                viewModel.chats?.let {
                    val chats = it.collectAsLazyPagingItems()
                    // layout for chats variable is here
                }
            }
        }
}
🧵 6
🧵 6
c
Set the initial load size https://developer.android.com/reference/kotlin/androidx/paging/PagingConfig#initialLoadSize() In the
PageConfig
- default might be 4*pagesize according to your observations.
m
Thank you for your suggestion! Now, it’s working has expected
z
Also, in the future, please keep long code dumps to the thread to keep the main channel less cluttered.