Восстановите позицию PagedListAdapter при возобновлении активности

Я экспериментировал с PagedListAdapter и не могу понять, как правильно восстановить положение адаптеров.

Последняя попытка была сохранить lastKey из текущего списка.

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)

    val lastKey = adapter.currentList?.lastKey as Int

    outState.putInt("lastKey", lastKey)
}

но при восстановлении моего адаптера и прохождении lastKey в PagedListBuilder То, что я видел в последний раз и что отображается, сильно отличается.

    val dataSourceFactory = dao.reportsDataSourceFactory()
    val builder = RxPagedListBuilder(
        dataSourceFactory,
        PagedList.Config.Builder()
            .setEnablePlaceholders(false)
            .setInitialLoadSizeHint(60)
            .setPageSize(20)
            .setPrefetchDistance(60)
            .build()
    )
        .setInitialLoadKey(initialLoadKey)
        .setBoundaryCallback(boundaryCallback)

Если при возобновлении я нахожусь в середине страницы № 4 - адаптер будет в положении в начале страницы № 4. В идеале адаптер должен быть восстановлен в том же положении, что и в последний раз.

Различные попытки сохранить состояние LayoutManager

outState.putParcelable("layout_manager_state", recycler_view.layoutManager.onSaveInstanceState()) 

а затем восстановить его

recycler_view.layoutManager.onRestoreInstanceState(it.getParcelable("layout_manager_state"))

с треском провалился. Любые предложения приветствуются:)

1 ответ

Решение

Наконец-то удалось заставить его работать.

Условие - ваше PagedListAdapter должен поддерживать нулевые заполнители! setEnablePlaceholders(true), Узнайте больше здесь

    val dataSourceFactory = dao.reportsDataSourceFactory()
    val builder = RxPagedListBuilder(
        dataSourceFactory,
        PagedList.Config.Builder()
            .setEnablePlaceholders(true) //in my original implementation it was false
            .setInitialLoadSizeHint(60)
            .setPageSize(20)
            .setPrefetchDistance(60)
            .build()
    )

Сохранить состояние как обычно:

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)

    val lastKey = adapter.currentList?.lastKey as Int

    outState.putInt("lastKey", lastKey)
    outState.putParcelable("layout_manager_state", recycler_view.layoutManager.onSaveInstanceState())
}

но при восстановлении - сначала сохраните состояние как переменную и восстановите сохраненное состояние только после отправки списка вPagedListAdapter

private fun showReports(pagedList: PagedList<Report>?) {
    adapter.submitList(pagedList)

    lastLayoutManagerState?.let {
        report_list.layoutManager.onRestoreInstanceState(lastLayoutManagerState)
        lastLayoutManagerState = null
    }
}

где lastLayoutManagerState является:

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)

    viewModel = withViewModel(viewModelFactory) {
        observe(reports, ::showReports)
    }

    report_list.adapter = adapter

    lastLayoutManagerState = savedInstanceState?.getParcelable("layout_manager_state")

    val lastKey = savedInstanceState?.getInt("lastKey")
    viewModel.getReports(lastKey)
}

Ох и когда обязателен ViewHolder в onBindViewHolder Я просто выручаю быстро, если элемент нулевой.

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    val item = getItem(position) ?: return
    ... 
}

Потому что он будет нулевым, так как в противном случае количество элементов адаптера не будет совпадать с количеством сохраненных элементов состояния (предположим здесь), и именно поэтому в некоторых из моих экспериментов макет прыгал на страницах 2+, пока он работал на странице 1.

Если есть лучшие способы, как подойти к этому без ручного хранения, а затем с помощью lastLayoutManagerState - дай мне знать.

Другие вопросы по тегам