architecture-samples icon indicating copy to clipboard operation
architecture-samples copied to clipboard

dev-todo-mvvm-rxjava: Tasks list is not restoring scroll position on config changes

Open sotojesus opened this issue 7 years ago • 1 comments

I guess this issue goes to @florina-muntenescu (who is the project owner).

I'm aware this branch is still under development, but I noticed this example is not handling restoring the scroll position properly on TasksFragment, instead, the scroll position gets reset to the top on orientation changes. I tested this by adding a lot of tasks to the list and then rotating my device.

I presume this is because the TasksFragment.updateView() method gets called after the layout pass of the activity and thus the RecyclerView does not know its correct size at rendering time.

It would be awesome if we are provided with a working example on how to restore the scroll position properly using MVVM and RxJava together.

Here is the link to TasksFragment.

Thank you for your help.

sotojesus avatar Aug 30 '18 22:08 sotojesus

Issue Summary Problem: Scroll position of the RecyclerView in TasksFragment resets to the top on configuration changes (e.g., device rotation).

Cause: Likely because TasksFragment.updateView() is called after the layout pass, so the RecyclerView doesn’t yet know its final size or the adapter isn't fully populated.

Technical Background In Android:

RecyclerView does not automatically retain scroll state unless:

RecyclerView.setStateRestorationPolicy() is correctly configured.

Or LayoutManager.onSaveInstanceState() and onRestoreInstanceState() are properly called manually.

On config change, if ViewModel emits new data (like a new LiveData<List<Task>>) after layout recreation, the scroll resets unless explicitly handled.

Recommended Fixes Option 1: Let RecyclerView Handle It Automatically Make sure:

recyclerView.setHasFixedSize(true) And your adapter restores state:

recyclerView.adapter?.stateRestorationPolicy = RecyclerView.Adapter.StateRestorationPolicy.ALLOW Option 2: Manually Save and Restore Scroll Position In TasksFragment:

private var layoutManagerState: Parcelable? = null

override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) layoutManagerState = recyclerView.layoutManager?.onSaveInstanceState() outState.putParcelable("layout_manager_state", layoutManagerState) }

override fun onViewStateRestored(savedInstanceState: Bundle?) { super.onViewStateRestored(savedInstanceState) layoutManagerState = savedInstanceState?.getParcelable("layout_manager_state") }

private fun restoreLayoutManagerState() { layoutManagerState?.let { recyclerView.layoutManager?.onRestoreInstanceState(it) } } Then call restoreLayoutManagerState() after the list is submitted in the adapter:

adapter.submitList(tasks) { restoreLayoutManagerState() } This ensures state is restored after the list has been fully laid out.

Summary This issue arises due to timing between data emission and layout restoration.

In MVVM + RxJava, scroll restoration must be manually handled, since new emissions on LiveData/Observable cause the adapter to re-bind and reset.

Using submitList(data) { restoreScrollPosition() } pattern after layout is key.

VaradGupta23 avatar Aug 04 '25 05:08 VaradGupta23