PageKeyedDataSource loadAfter вызывается непрерывно - PullRequest
5 голосов
/ 06 ноября 2019

У меня есть PageKeyedDataSource, который постоянно вызывает loadAfter, и все элементы добавляются в Recyclerview несколько раз. Со стороны 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
        }
    }

1 Ответ

1 голос
/ 08 ноября 2019

Код выглядит в основном нормально, но кажется странным, что вы превращаете следующую часть ответа в строку с помощью toString и используете ее в качестве ключа.

Вместо PageKeyedDataSource<String, Reservation?>,попробуйте PageKeyedDataSource<KeyType, Reservation> (не уверен, какой тип этого ключа из приведенного выше кода).

Затем вы можете взять следующий токен непосредственно из API и передать его в параметр last вашего API. без его изменения.

Вы также должны использовать ненулевое значение Reservation - библиотека подкачки ожидает, что загруженные элементы не равны NULL, поскольку нулевые значения зарезервированы для представления заполнителей: https://developer.android.com/reference/androidx/paging/DataSource#implementing-a-datasource

...