How to retain RecyclerView's position after Orientation change, while using Firebase & ChildEventListener?
While rotation activity get destroyed and re-created once again that means all your objects destroyed and re-created and also layout re-drawn again.
It you want to stop re-creation of activity you can use android:configChanges but it is bad practice and also not the right way.
Only thing remains now is to save position of recyclerview before rotation and get it after activity re-created.
// to save recyclerview position
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save UI state changes to the savedInstanceState.
// This bundle will be passed to onCreate if the process is
// killed and restarted.
savedInstanceState.putInt("position", mRecyclerView.getAdapterPosition()); // get current recycle view position here.
super.onSaveInstanceState(savedInstanceState);
}
// to restore value
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
setContentView(R.layout.activity_main);
getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
final int columns = getResources().getInteger(R.integer.gallery_columns);
mDatabaseReference = FirebaseDatabase.getInstance().getReference();
query = mDatabaseReference.child("apod").orderByChild("date");
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new GridLayoutManager(this, columns));
mRecyclerAdapter = new RecyclerAdapter(this, query);
mRecyclerView.setAdapter(mRecyclerAdapter);
if(savedInstanceState != null){
// scroll to existing position which exist before rotation.
mRecyclerView.scrollToPosition(savedInstanceState.getInt("position"));
}
}
Hope these help you.
EDIT:
I was finally able to make this work using multiple factors. If any one of these were left out, it simply would not work.
Create new GridLayoutManager
in my onCreate
gridLayoutManager = new GridLayoutManager(getApplicationContext(), columns);
Save the RecyclerView state in onPause
private final String KEY_RECYCLER_STATE = "recycler_state";
private static Bundle mBundleRecyclerViewState;
private Parcelable mListState = null;`
@Override
protected void onPause() {
super.onPause();
mBundleRecyclerViewState = new Bundle();
mListState = mRecyclerView.getLayoutManager().onSaveInstanceState();
mBundleRecyclerViewState.putParcelable(KEY_RECYCLER_STATE, mListState);
}
Include configChanges
in the AndroidManifest.xml
Saving and restoring the RecyclerView
state was not enough. I also had to go against the grain and change my AndroidManifest.xml
to 'android:configChanges="orientation|screenSize"'
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize"
>
Restore the RecyclerView
state in onConfigurationChanged
using a Handler
The handler was one of the most important parts, if it's not included, it simply will not work and the position of the RecyclerView
will reset to 0. I guess this has been a flaw going back a few years, and was never fixed. I then changed the GridLayoutManager
's setSpanCount
depending on the orientation.
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
columns = getResources().getInteger(R.integer.gallery_columns);
if (mBundleRecyclerViewState != null) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mListState = mBundleRecyclerViewState.getParcelable(KEY_RECYCLER_STATE);
mRecyclerView.getLayoutManager().onRestoreInstanceState(mListState);
}
}, 50);
}
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
gridLayoutManager.setSpanCount(columns);
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
gridLayoutManager.setSpanCount(columns);
}
mRecyclerView.setLayoutManager(gridLayoutManager);
}
Like I said, all of these changes needed to be included, at least for me. I don't know if this is the most efficient way, but after spending many hours, it works for me.