【问题标题】:PageKeyedDataSource loadAfter called continuouslyPageKeyedDataSource loadAfter 连续调用
【发布时间】:2019-11-06 17:19:16
【问题描述】:

我有一个PageKeyedDataSource,不断调用loadAfter,在Recyclerview中多次添加所有item。从 API 方面来看,一个空 lastEvaluatedKey 意味着给我第一页,这对于为什么它一直调用以获取第一页但 A 有点道理。如果没有更多数据要获取,它是否应该停止(又名 params.key == null ? 和 B. 适配器中的 COMPARATOR 不应该不允许多次添加相同的项目吗?我错过了什么?

PageKeyedDataSource.kt

class ReservationsPageKeyedDataSource(private val retryExecutor: Executor) : PageKeyedDataSource<String, Reservation?>() {

    private var retry: (() -> Any)? = null

    val initialLoad = MutableLiveData<PagingNetworkState>()

    fun retryAllFailed() {
        val prevRetry = retry
        retry = null
        prevRetry?.let {
            retryExecutor.execute {
                it.invoke()
            }
        }
    }

    override fun loadInitial(
        params: LoadInitialParams<String>,
        callback: LoadInitialCallback<String, Reservation?>
    ) {
        val request = Api.reservationsService.getReservations(dateType = RERVATIONS_DATE_TYPE.future, last = null)

        initialLoad.postValue(PagingNetworkState.LOADING)

        // triggered by a refresh, execute in sync
        try {
            val response = request.execute()
            val originalData = response.body()?.result?.reservations
            val data = mutableListOf<Reservation>()
            // some data munipulation
            retry = null
            initialLoad.postValue(PagingNetworkState.LOADED)

            callback.onResult(
                data.toList(),
                null,
                response.body()?.result?.lastEvaluatedKey.toString()
            )
        } catch (ioException: IOException) {
            retry = {
                loadInitial(params, callback)
            }
            val error = PagingNetworkState.error(ioException.message ?: "unknown error")
            initialLoad.postValue(error)
        }
    }

    override fun loadBefore(
        params: LoadParams<String>,
        callback: LoadCallback<String, Reservation?>
    ) {
        // no-op
    }

    override fun loadAfter(
        params: LoadParams<String>,
        callback: LoadCallback<String, Reservation?>
    ) {

        // I tried adding an if statement here to check if the params.key is null or not but that didn't help

        Api.reservationsService.getReservations(dateType = RERVATIONS_DATE_TYPE.future, last = params.key)
            .enqueue(object : Callback<ReservationListResponse> {
                override fun onFailure(call: Call<ReservationListResponse>, t: Throwable) {
                    retry = { loadAfter(params, callback) }
                }

                override fun onResponse(
                    call: Call<ReservationListResponse>,
                    response: Response<ReservationListResponse>
                ) {
                    if (response.isSuccessful) {
                        val data = response.body()?.result?.reservations
                        retry = null
                        callback.onResult(
                            data.orEmpty(),
                            response.body()?.result?.lastEvaluatedKey.toString()
                        )
                    } else {
                        retry = { loadAfter(params, callback) }
                    }
                }
            })
    }
}

PagedListAdapter 中的比较器:

companion object {
        val COMPARATOR = object : DiffUtil.ItemCallback<Reservation>() {
            override fun areContentsTheSame(oldItem: Reservation, newItem: Reservation): Boolean =
                oldItem == newItem

            override fun areItemsTheSame(oldItem: Reservation, newItem: Reservation): Boolean =
                oldItem.id == newItem.id
        }
    }

【问题讨论】:

    标签: kotlin android-architecture-components android-paging


    【解决方案1】:

    另一个可能的原因是,如果您在 ScrollView 内部使用 Recycleview,loadAfter 将被无限调用,直到数据完成。 Recycleview 会自动处理滚动,所以不要在 scrollView 中使用它。

    【讨论】:

    • 谢谢你,你拯救了我的一天!我确认 - 如果您在 NestedScrollView 中使用 RecyclerView,loadAfter() 会在任何滚动时连续调用。
    • 非常感谢!这确实解决了我的问题,我在NestedScrollView 中有一个RecyclerView
    • 我在NestedScrollView 里面有一个RecyclerView insideConstraintLayout。由于我在 &lt;include layout=""/&gt; 标记下定义了其他 UI 项目以及 ConstraintLayout 中的 RecyclerView,因此我通过在单独的适配器中添加 RecyclerView 以外的 UI 项目解决了这个问题,并使用 ConcatAdapter 合并新创建的带有PagedAdapter 的适配器。
    【解决方案2】:

    代码看起来大部分都很好,但是您通过 toString 将响应的下一个标记部分转换为字符串并将其用作密钥似乎很奇怪。

    试试PageKeyedDataSource&lt;KeyType, Reservation&gt;,而不是PageKeyedDataSource&lt;String, Reservation?&gt;(从上面的代码中不确定该键的类型)。

    然后您可以直接从 API 中获取下一个令牌,并将其传递到您的 API 的 last 参数中,而无需修改它。

    您还应该使用不可为空的Reservation - Paging 库期望加载的项目是非空的,因为空值是为表示占位符而保留的:https://developer.android.com/reference/androidx/paging/DataSource#implementing-a-datasource

    【讨论】:

    • 当我有一个项目也加载后调用并重复,为什么?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-03
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多