Firebaseui-android: FirebaseRecyclerAdapter and RecyclerView scroll position is lost on orientation change

Created on 6 Nov 2017  路  15Comments  路  Source: firebase/FirebaseUI-Android

Environment

  • Android device: API 27 Emulator / Google Pixel
  • Android OS version: 27 / 8.0.0
  • Google Play Services version: whatever the emulator has / 11.7.45 (940-174122868)
  • Firebase/Play Services SDK version: 11.4.2
  • FirebaseUI version: 3.1.0

The problem:

On orientation change the recycler view using FirebaseRecyclerAdapter looses it's scroll position and is always scrolled to the top.

Steps to reproduce:

  1. In the https://github.com/firebase/FirebaseUI-Android/blob/master/app/src/main/java/com/firebase/uidemo/database/realtime/RealtimeDbChatActivity.java#L110 comment out:
        // Scroll to bottom on new messages
        adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
            @Override
            public void onItemRangeInserted(int positionStart, int itemCount) {
                mRecyclerView.smoothScrollToPosition(adapter.getItemCount());
            }
        });

so it does not get execute. This is needed so there is no extra logic forcing a scroll position.

  1. Build the demo app
  2. Add a bunch of chat messages, a lot so you get a scrolling regardless of orientation
  3. Scroll neither to the top nor the bottom
  4. Rotate the emulator

Observed Results:

  • After rotation the recycler view lost it's scroll position and is scrolled to the top.

Expected Results:

  • The recycler view should keep it's scroll position on orientation change.

Most helpful comment

@SUPERCILEX I solved my problem with a simpler solution. I just called adapter.startListening(); in onViewCreated() instead of onStart and called adapter.stopListening(); in onDestroyView() instead of onStop()
That prevented the entire list from regenerating while coming back from next activity and thus retained the scroll position where it was previously.

All 15 comments

@Calebzor This is expected behavior because FirebaseUI doesn't have a stable data source鈥攖hat is, we have to resubscribe and regenerate the entire list on each screen rotation. However, using Android Architecture Components, you can fairly easily keep a FirestoreArray instance to keep alive across config changes.

I have a project with (probably) too much infrastructure to make things easily understandable, but it will hopefully help you understand my explanation. Here's a high level overview:

  • Create a ViewHolder that can take in ObservableSnapshotArrays and provides an exposed api to get them back. This will be used across your app.
  • In the ViewHolder, add a no-op subscription to the array so that it starts a connection to the database
  • In your Activity/Fragment, pass in the snapshot array to the adapter and a LifecycleOwner
  • Now you have a stable data source that will survive across config changes. To save the user's battery, make sure to check out ListenerRegistrationLifecycleOwner
  • In your ViewHolder's onCleared() method, kill the snapshot array
  • Voila! 馃槃

@samtstern Since the above is a bit much, do you think we should provide that functionality out of the box? I'd have to spend way more time thinking about the APIs, but I definitely think it's possible without too much messiness.

Oh lol, as I was looking through my code to explain this I found a bug. Thanks for helping me find a bug?
馃槅 Anyway, I've updated the commit references to include the bugfix.

I also experience a similar issue. The scroll position is not retained when returning back from next screen and the screen goes back to first item on recycler view list. How to solve it?

See my answer above.

@SUPERCILEX I solved my problem with a simpler solution. I just called adapter.startListening(); in onViewCreated() instead of onStart and called adapter.stopListening(); in onDestroyView() instead of onStop()
That prevented the entire list from regenerating while coming back from next activity and thus retained the scroll position where it was previously.

Thanks everyone for commenting! This seems like it's working as intended from the FBUI perspective, so closing the issue.

@ncherian that works for the simple case but doesn't address screen rotations. When you get to that point in development, feel free to come back to this comment. 馃槃

@samtstern what do you think of https://github.com/firebase/FirebaseUI-Android/issues/998#issuecomment-342333313?

@SUPERCILEX @ncherian hi im new to android development.. how can i get it done? can you give me detailed instruction on how can i get it done it?

@ncherian how did u do it ? please can u help me !!

Problem solved !

@SUPERCILEX I'm not familiar with kotlin. Do you have example code on java? Thanks for the great help.

@Roxytsai unfortunately not since the app is in production. It would be a great way to dip your feet in Kotlin though! And if you have questions, feel free to ask them. 馃榾

@SUPERCILEX Thanks for your suggestion, I'm studying Kotlin now. Owing to Robot-Scouter app still too complex for me, do you have Quickstart code about how to solve scroll position in FirestoreRecyclerAdapter by using ObservableSnapshotArray.
Anyway, thanks for your feedback.

@SUPERCILEX Thanks for your suggestion, I resolved it! Many thanks~

In my case, I didn't want move to a specific position, instead I just wanted to keep the original position after returning from a different Activity or returning from background.

I just added this empty listener and it's working.

 listAdapter.snapshots.addChangeEventListener(object : ChangeEventListener {
        override fun onChildChanged(
            type: ChangeEventType,
            snapshot: DocumentSnapshot,
            newIndex: Int,
            oldIndex: Int
        ) {
        }

        override fun onDataChanged() {
        }

        override fun onError(e: FirebaseFirestoreException) {
        }
    })

Here listAdapter is FirestoreRecyclerAdapter.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ghost picture ghost  路  5Comments

Nebneb picture Nebneb  路  3Comments

long1eu picture long1eu  路  4Comments

samtstern picture samtstern  路  3Comments

RedCider picture RedCider  路  5Comments