Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Append data after load in Remote Mediator

Đang mở
#247 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
38/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Đình trệ
Công nghệ
android, kotlin
Lĩnh vực
mobile

Hướng nghiên cứu

Bắt đầu bằng cách lần theo luồng Pager qua MapPagingSource.load và PokemonApiRemoteMediator.load, sau đó so sánh chuỗi được ghi log với PagingData được gửi đến adapter. Kiểm tra cách map trong bộ nhớ thay đổi trong APPEND và sự kiện nào sẽ làm cho dữ liệu vừa tải trở nên hiển thị. Được coi là hoàn tất khi các kết quả được nối thêm xuất hiện trong adapter mà không phụ thuộc vào một workaround không liên quan.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

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

Ngôn ngữ chính
Kotlin
Star
509
Fork
268
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của android/codelab-android-paging

Tất cả issue của android/codelab-android-paging

Issue tương tự

Thêm issue về Kotlin

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.