androidandroid-recyclerviewrotationandroid-viewpagerandroid-configchanges

Determine if fragment restart is due to screen rotation or Viewpager swipe?


I have an Activity with ViewPager. the ViewPager have a lot of pages, Just like a book. Each fragment has RecyclerViews with a lot of content. The following is my use case

1 - When I swipe page, RecyclerView must start from the beginning of the list. 2. If I rotate my device, It should read from exact last position of where I left before rotation.

If I don't use any logic, 2nd scenario works perfectly. ie, rotation. But not the first scenario.

If I do some logic like below. Helps to achieve first scenario, But not the second scenario.

  @Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
    if (savedInstanceState==null) {
        mIsFirstTime = true;
    }
}

@Override
public void onResume() {
    super.onResume();
    try {
        getActivity().invalidateOptionsMenu();
            if (!mIsFirstTime) {
                mListView.scrollToPosition(0);                
            }
    } catch (Exception e) {
        e.printStackTrace();
    }

}

So My question is

How can I determine a fragment restart is due to screen rotation or Viewpager swipe?

I already tried onConfigurationChanged(Configuration newConfig) . But it doesn't help me. Could you please help me


Solution

  • From a comment of OP:

    My question is how I know that onSaveInstanceState() is called due to screen orientation change and not fragment restart

    You can do that via Activity#isChangingConfigurations() API.

    
        @Override
        protected void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
    
            if (isChangingConfigurations()) {
                // this callback is executed as a result of a configuration change (e.g. orientation change)
            } else {
                // no configuration change happens (e.g. a click on a home button would end up here)
            }
        }
    
    

    Now you can save a boolean value into Bundle outState and appropriate setup UI after recreation:

    
        @Override
        protected void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            outState.putBoolean("isConfigurationChange", isChangingConfigurations());
        }
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            // initialization logics here
    
            if (savedInstanceState != null) {
                boolean isConfigurationChange = savedInstanceState.getBoolean("isConfigurationChange");
    
                // if `onCreate` is called as a result of configuration change
                if (isConfigurationChange) {
                    // view hierarchy is not yet laid out, have to post an action 
                    listView.post(new Runnable() {
                        @Override
                        public void run() {
                            // we are guaranteed, that `listView` is already laid out
                            listView.scrollToPosition(0);
                        }
                    });
                }
            }
        }
    
    

    Note, that performing boolean value checking logics inside onResume() is a bug (pressing home button and navigating back to the app would result in scrolling to the top again, which is not desired). Instead onCreate() should be chosen as a correct callback.