PageKeyedDataSource load连续调用后

时间:2019-11-06 17:19:16

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

我有一个连续调用loadAfter的PageKeyedDataSource,并且所有项目都多次添加到Recyclerview中。从API方面来说,空lastEvaluatedKey意味着给我第一页,这对于为什么它不断调用以获取第一页却是A很有道理。如果没有更多数据要获取,它就应该停止(aka { {1}}?和B.适配器中的params.key == null是否不应不允许多次添加相同的项目?我会丢失什么?

PageKeyedDataSource.kt

COMPARATOR

PagedListAdapter中的比较器:

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) }
                    }
                }
            })
    }
}

2 个答案:

答案 0 :(得分:1)

该代码看起来基本上没问题,但是奇怪的是,您将响应的下一个标记部分通过toString转换为字符串,并将其用作键。

尝试使用PageKeyedDataSource<String, Reservation?>而不是PageKeyedDataSource<KeyType, Reservation>(不确定上面代码中的密钥类型)。

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

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

答案 1 :(得分:0)

另一个可能的原因是,如果在ScrollView的内部使用Recycleview,则loadAfter将被无限调用,直到完成数据为止。 Recycleview将自动处理滚动,因此请勿在scrollView中使用它。