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.