Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

Append data after load in Remote Mediator

Abierto
#247 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
38/100
Tipo de issue
Error
Claridad
Bastante claro
Estado de actividad
Estancado
Stack tecnológico
android, kotlin
Área
mobile

Línea de trabajo

Empieza siguiendo el flujo de Pager a través de MapPagingSource.load y PokemonApiRemoteMediator.load, y después compara la secuencia registrada con el PagingData enviado al adapter. Comprueba cómo cambia el mapa en memoria durante APPEND y qué evento debería hacer visibles los datos recién cargados. Se considera terminado cuando los resultados añadidos aparecen en el adapter sin depender de un workaround no relacionado.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

I decided to try Pager without the Room database. I use HashMap as the simplest database.
First I implemented PagingSource.

class MapPagingSource(
    private val map: () -> Map<Int, List<Result>>
) : PagingSource<Int, Result>() {

    override fun getRefreshKey(state: PagingState<Int, Result>): Int? {
        println("TAG PagingSource anchorPosition  ${state.anchorPosition}")
        val anchor = state.anchorPosition ?: return null
        val closest = state.closestPageToPosition(anchor) ?: return null
        val page  = closest.prevKey?.plus(1) ?: closest.nextKey?.minus(1)
        return page
    }

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Result> {
        val map = map()
        val position = (params.key ?: 0)
        println("TAG PagingSource position = $position, size = ${map.size}")
        return LoadResult.Page(
            data = map[position] ?: emptyList(),
            prevKey = if (position == 0) null else position - 1,
            nextKey = if (position + 1 < map.size) position + 1 else null
        )
    }
    
}

After RemoteMediator

@OptIn(ExperimentalPagingApi::class)
class PokemonApiRemoteMediator(
    private val map: () -> MutableMap<Int, List<Result>>,
    private val append: () -> Unit
) : RemoteMediator<Int, Result>() {

    private val ktor = Ktor()

    override suspend fun initialize(): InitializeAction {
        println("TAG RemoteMediator initialize")
        return InitializeAction.LAUNCH_INITIAL_REFRESH
    }

    override suspend fun load(loadType: LoadType, state: PagingState<Int, Result>): MediatorResult {
        val map = map()
        println("TAG RemoteMediator $loadType, ${map.size}")
        return try {
            val latestPage = when (loadType) {
                LoadType.REFRESH -> 0
                LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
                LoadType.APPEND -> map.size
            }
            val subList = runCatching {
                withContext(Dispatchers.IO) {
                    ktor.getData(state.config.pageSize, latestPage * state.config.pageSize)
                }
            }.getOrNull()

            val data =
                subList?.results ?: return MediatorResult.Success(endOfPaginationReached = true)
            if (data.isEmpty()) return MediatorResult.Success(endOfPaginationReached = true)

            if (loadType == LoadType.REFRESH) map.clear()
            map[latestPage] = data

            println("TAG RemoteMediator size ${map.size}")
            if (loadType == LoadType.APPEND) append()
            MediatorResult.Success(false)
        } catch (e: Throwable) {
            println("TAG RemoteMediator $e")
            MediatorResult.Error(e)
        }
    }
}

And created a Pager in ViewModel

    private val data: MutableMap<Int, List<Result>> = HashMap()
    private var latestSource: MapPagingSource? = null

    @OptIn(ExperimentalPagingApi::class)
    private val _pager = Pager(
        config = PagingConfig(10, enablePlaceholders = false),
        remoteMediator = PokemonApiRemoteMediator(map = { data }) { },
        pagingSourceFactory = {
            println("TAG create source")
            MapPagingSource { data }.also {
            latestSource = it
        } }
    val adapter = Adapter()

    init {
        _pager.flow
            .onEach {
                println("TAG PagingData $it")
                adapter.submitData(it)
            }.launchIn(viewModelScope)
    }

photo_2024-12-08_03-00-26

As I can see, the PagingData was created and sent to the adapter.
Then the PagingSource did not find the data and started the RemoteMediator.
After loading, the work stopped and the PagingSource did not start loading the data.
Of course, I can call "invalidate". But this will recreate the PagingSource, and will not add the data as if it were just making requests to the network from the PagingSource.
photo_2024-12-08_03-00-52

Lenguaje dominante
Kotlin
Estrellas
509
Forks
268
Métricas de merge de PR
Sin PR fusionados en 30 d

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de android/codelab-android-paging

Todos los issues de android/codelab-android-paging

Issues similares

Más issues de Kotlin

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.