0

I designed an app using jetpack-navigation There is a problem as illustrated in the following image when I move from one fragment to another one the status of the list disappears.

In fact, when returning from a layout, the article will be re-created in the stack and the list status will not be saved and the user will have to scroll again. Please help me?

jetpack-navigation

2 Answers2

0

The fragment gets recreated on every navigation operation. You could store the scroll position in your activity and load it from there. But doing it like this, the scroll position will be lost on activity recreate (e.g. rotating device).

Better approch would be to store it in a ViewModel. (see https://developer.android.com/topic/libraries/architecture/viewmodel)

The view model survives activity recreation and you can store your scroll position.

Then you can load this position and tell the list to scroll to this position (e.g. for RecyclerView with LinearLayoutManager by calling scrollToPositionWithOffset(...))

dtzkwa34
  • 160
  • 1
  • 1
  • 9
  • thank for answer but how store state in pagination list if load page 3 lost position in back – Ali Mousavi Nov 04 '19 at 12:19
  • 3
    `Better approach would be to store it in a ViewModel.` now if the user puts the app in background, then opens Camera, Google Photos, then shares a picture to Facebook, and returns to your app; your scroll position will still be lost. This should be persisted via `onSaveInstanceState`. More importantly, with proper setup of view IDs and adapters and layout manager, the restoration of the scroll position should actually be automatic, even on back navigation. It only gets overridden if a different adapter with different items is set before actually setting back the previous data set. – EpicPandaForce Nov 04 '19 at 12:26
  • You should read https://developer.android.com/topic/libraries/architecture/saving-states#options_for_preserving_ui_state and https://developer.android.com/docs/quality-guidelines/core-app-quality and https://stackoverflow.com/questions/49046773/singleton-object-becomes-null-after-app-is-resumed/49107399#49107399 – EpicPandaForce Nov 04 '19 at 12:29
0

I'm reloading recyclerView data every 15s. To keep scroll position when switching between apps, I use onSaveInstanceState() and onRestoreInstanceState(mRVState) methods in corresponding fragment overriden methods. But when I wanted to save position while switching between different fragments, I came up with this solution:

1.Set RecyclerView.OnScrollListener() in onResume() method of Fragment and get current first visible item position on each scroll. As you can see position variable is located in parent activity, so it's not lost on fragment replacement:

override fun onResume() {
        super.onResume()
        if (updateListRunnable != null) setAndRunUpdateListRunnable()
        mRV?.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                mainActivity.lastRVPosition =
                        (recyclerView.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition()
            }
        })
    }

2.Use scrollToPosition() method of recyclerView after data has been replaced inside adapter:

private fun setDataList(dataList: List<Data?>?) {
        val mutableDataList = dataList?.toMutableList()
        val currentItemCount = binding?.rvDataList?.adapter?.itemCount
        if (currentItemCount == null || currentItemCount == 0) {
            // create new adapter with initial data
            val adapter = DataListAdapter(mutableDataList, baseVM, mainVM)
            binding?.rvDataList?.adapter = adapter
            binding?.rvDataList?.layoutManager = LinearLayoutManager(context)
            mRV?.scrollToPosition(mainActivity.lastRVPosition);
        } else {
            // update existing adapter with updated data
            mRVState = mRV?.layoutManager?.onSaveInstanceState()
            val currentAdapter = binding?.rvDataList?.adapter as? DataListAdapter
            currentAdapter?.updateDataList(dataList)
            currentAdapter?.notifyDataSetChanged()
            mRV?.layoutManager?.onRestoreInstanceState(mRVState)
            mRV?.scrollToPosition(mainActivity.lastRVPosition);
        }
    }

As you can see I also use onSaveInstanceState()/onRestoreInstanceState() before/after replacing data, so that if there was no scroll before data replacement, position will still be saved. Scroll listener saved position is only useful when switching between fragments.

Neone
  • 482
  • 1
  • 9
  • 21