web-dev-qa-db-ja.com

アクティビティを再開するときにPagedListAdapterの位置を復元する

PagedListAdapterを試していましたが、アダプターの位置を正しく復元する方法がわかりません。

最後の試みは、現在のリストからlastKeyを保存することでした。

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

    val lastKey = adapter.currentList?.lastKey as Int

    outState.putInt("lastKey", lastKey)
}

しかし、アダプタを復元してlastKeyPagedListBuilderに渡すと、最後に見たものと表示されているものがかなり異なります。

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

惨めに失敗した。任意の提案を歓迎します:)

13
Martynas Jurkus

ついにそれを機能させることができました。

前提条件-PagedListAdapterはnullプレースホルダーをサポートする必要があります! 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)
}

ああ、ViewHolderonBindViewHolderにバインドするとき、アイテムがnullの場合はすぐに救済します。

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

アダプターのアイテム数が保存された状態のアイテム数と一致しないため、nullになります(ここで推測します)。そのため、一部の実験では、レイアウトが1ページで機能しているときに2ページ目でジャンプしていました。

手動で保存してからlastLayoutManagerStateを使用せずにこれにアプローチするより良い方法がある場合は、私に知らせてください。

8
Martynas Jurkus