Update: It turns out that the problem is from elsewhere. Thanks @Luksprog for pointing out what I overlooked.
- The project is created using Android Studio's navigation drawer pattern. The drawer is implemented in the
NavigationDrawerFragment
class. - The fragment holding the view pager is added when a particular item in the drawer is selected. The code is implemented my home activity.
- When screen rotates, the
onCreate()
method ofNavigationDrawerFragment
is called, preserving last selected item. - And here is what went wrong - upon recreation,
NavigationDrawerFragment
will call selectItem() again, which triggers my menu item selected handler. This causes the ListFragment restored by Android.
This can be prevented by checking the active menu item in my menu selection handler code.
I want to retain the last viewing page index of the ViewPager
when the activity is recreated by whatever reason, e.g. orientation change.
The ViewPager
is in a Fragment
(named ListFragment
), which is attached to an activity. I am using the compat library, so the fragment is a subclass of android.support.v4.app.Fragment
.
I thought that it could be done by overriding the onSaveInstanceState()
method and add appropriate logic in onCreate()
, as metioned in the doc:
To properly handle a restart, it is important that your activity restores its previous state through the normal Activity lifecycle, in which Android calls onSaveInstanceState() before it destroys your activity so that you can save data about the application state. You can then restore the state during onCreate() or onRestoreInstanceState().
But the situation seems different for fragments. The page index can be correctly restored when I navigate from this ListFragment
to another activity and pressed "back". However when I rotate my device, the page index is lost.
I added some logging to see what's wrong. From the log I found that although onSaveInstanceState()
of the ListFragment
(I'll call it ListFragment A) is called properly, this particular Fragment class is no longer shown in the activity. When the orientation changed and the activity is recreated, Android calls onSaveInstanceState()
followed by onDetach()
to detach this fragment. Then Android creates a new instance of ListFragment
(I'll call it ListFragment B) and attach it to the new, rotated activity. This ListFragment B has an empty savedInstanceState
passed to the constructor, and thus the last page index (and any configuration in savedInstanceState of Fragment A) is lost.
In fact, a new instance of ListFragment
will be created every time a screen rotate occurs, but it seems that the old ones will not be destroyed. I see logs like below when I rotate the device:
D/ListFragment﹕ [1110257048] onSaveInstanceState() called, storing last page index 3
D/ListFragment﹕ [1109835992] onSaveInstanceState() called, storing last page index 0
D/ListFragment﹕ [1108826176] onSaveInstanceState() called, storing last page index 0
D/ListFragment﹕ [1108083096] onSaveInstanceState() called, storing last page index 0
D/ListFragment﹕ [1106541040] onSaveInstanceState() called, storing last page index 0
D/ListFragment﹕ [1108316656] onSaveInstanceState() called, storing last page index 0
D/ListFragment﹕ [1109134136] onSaveInstanceState() called, storing last page index 0
D/ListFragment﹕ [1108630992] onSaveInstanceState() called, storing last page index 0
D/ListFragment﹕ [1108592888] onSaveInstanceState() called, storing last page index 0
D/ListFragment﹕ [1109729064] onSaveInstanceState() called, storing last page index 0
D/ListFragment﹕ [1110257048] onDestroy()
D/ListFragment﹕ [1110257048] onDetach()
D/ListFragment﹕ [1109835992] onDestroy()
D/ListFragment﹕ [1109835992] onDetach()
D/ListFragment﹕ [1108826176] onDestroy()
D/ListFragment﹕ [1108826176] onDetach()
D/ListFragment﹕ [1108083096] onDestroy()
D/ListFragment﹕ [1108083096] onDetach()
D/ListFragment﹕ [1106541040] onDestroy()
D/ListFragment﹕ [1106541040] onDetach()
D/ListFragment﹕ [1108316656] onDestroy()
D/ListFragment﹕ [1108316656] onDetach()
D/ListFragment﹕ [1109134136] onDestroy()
D/ListFragment﹕ [1109134136] onDetach()
D/ListFragment﹕ [1108630992] onDestroy()
D/ListFragment﹕ [1108630992] onDetach()
D/ListFragment﹕ [1108592888] onDestroy()
D/ListFragment﹕ [1108592888] onDetach()
D/ListFragment﹕ [1109729064] onDestroy()
D/ListFragment﹕ [1109729064] onDetach()
D/ListFragment﹕ [1110903656] onAttach()
D/ListFragment﹕ [1110903656] onCreate()
D/ListFragment﹕ [1110903656] savedInstanceState is not NULL.
D/ListFragment﹕ [1110903656] Retrieving last page index 3
D/ListFragment﹕ [1110905248] onAttach()
D/ListFragment﹕ [1110905248] onCreate()
D/ListFragment﹕ [1110905248] savedInstanceState is not NULL.
D/ListFragment﹕ [1110905248] Retrieving last page index 0
D/ListFragment﹕ [1110906440] onAttach()
D/ListFragment﹕ [1110906440] onCreate()
D/ListFragment﹕ [1110906440] savedInstanceState is not NULL.
D/ListFragment﹕ [1110906440] Retrieving last page index 0
D/ListFragment﹕ [1110907632] onAttach()
D/ListFragment﹕ [1110907632] onCreate()
D/ListFragment﹕ [1110907632] savedInstanceState is not NULL.
D/ListFragment﹕ [1110907632] Retrieving last page index 0
D/ListFragment﹕ [1110908824] onAttach()
D/ListFragment﹕ [1110908824] onCreate()
D/ListFragment﹕ [1110908824] savedInstanceState is not NULL.
D/ListFragment﹕ [1110908824] Retrieving last page index 0
D/ListFragment﹕ [1110910016] onAttach()
D/ListFragment﹕ [1110910016] onCreate()
D/ListFragment﹕ [1110910016] savedInstanceState is not NULL.
D/ListFragment﹕ [1110910016] Retrieving last page index 0
D/ListFragment﹕ [1110911208] onAttach()
D/ListFragment﹕ [1110911208] onCreate()
D/ListFragment﹕ [1110911208] savedInstanceState is not NULL.
D/ListFragment﹕ [1110911208] Retrieving last page index 0
D/ListFragment﹕ [1110912400] onAttach()
D/ListFragment﹕ [1110912400] onCreate()
D/ListFragment﹕ [1110912400] savedInstanceState is not NULL.
D/ListFragment﹕ [1110912400] Retrieving last page index 0
D/ListFragment﹕ [1110913592] onAttach()
D/ListFragment﹕ [1110913592] onCreate()
D/ListFragment﹕ [1110913592] savedInstanceState is not NULL.
D/ListFragment﹕ [1110913592] Retrieving last page index 0
D/ListFragment﹕ [1110914784] onAttach()
D/ListFragment﹕ [1110914784] onCreate()
D/ListFragment﹕ [1110914784] savedInstanceState is not NULL.
D/ListFragment﹕ [1110914784] Retrieving last page index 0
D/HomeActivity﹕ fragment updated
D/ListFragment﹕ [1110914784] onCreateView()
D/ListFragment﹕ [1111031048] onAttach()
D/HomeActivity﹕ Fragment attached.
D/ListFragment﹕ [1111031048] onCreate()
D/ListFragment﹕ [1111031048] savedInstanceState is NULL.
D/ListFragment﹕ [1111031048] onCreateView()
D/ListFragment﹕ [1111031048] onResume(), restoring page index 0
This is the log after I rotated the screen for about 10 times. The number in the tag is the classes' hashCode()
. Above lines shows that onSaveInstanceState()
and onCreate()
of the previously created fragments still get called even after they are replaced by the latest (1111031048) one.
Note that I didn't call setRetainInstance()
in the fragment class. In fact, I tried both setRetainInstance(false)
and setRetainInstance(true)
but it doesn't change anything.
Did I do anything wrong here? I can understand that ListFragment
needs to be recreated, but why savedInstanceState
is null? And if this is the expected behavior, what is the correct way to solve my need, i.e. keeping the page index when configuration changes?
It should be possible to make the page index a static class variable, but I'm not sure if it is actually solving the issue, or just hiding it (because I smell memory leak in the log above).
super
on all overrided activity and fragment methods (likeonCreate
,onSaveInstanceState
) and so on? – FeelerViewPager
isn't added again(by mistake) by your code after the rotation, replacing the saved one? – Garber