How to handle savedInstanceState when using ViewPager? - android

I'm using android.support.v4.view.ViewPager in an application.
When the user rotates the screen, the activity is destroyed and recreated. The fragments that are currently active in the ViewPager (usually the one on screen, the one to the left of it, and the one to the right of it) are all stored to the savedInstanceState.
A new activity is created, FragmentActivity.onCreate(savedInstanceState) is called with the fragment state, and those three fragments are re-created using the bundle. However, my onCreate also sets up the ViewPager and ViewPager adapter, which create their own fragments afresh, thus resulting in TWO of each of those three fragments.
How can I associate the automatically re-created fragments with my ViewPager's adapter rather than re-creating them from scratch?

Never mind. It appears that I was using FragmentPagerAdapter incorrectly.
The correct way to use FragmentPagerAdapter is to instantiate your new fragment in getItem(). I was instantiating all my fragments in the adapter's constructor instead, storing them in an array, and then looking them up in the array and returning the appropriate fragment in getItem().
If you instantiate your fragment from getItem(), then FragmentPagerAdapter.instantiateItem() will automatically use the recycle fragment instead of instantiating a new one.

Related

Save state of dynamic ViewPager

I have an android app in which I want to dynamically add and remove Fragments to a ViewPager during runtime, and preserving the Fragments on configuration changes.
Thus far I have implemented a FragmentStatePagerAdapter, holding my Fragments in a list with methods add, remove and replace to manipulate my Fragments. Basically, all they do is insert or delete a Fragment in the list and then call notifyDatasetChanged(). I insert the staring Fragment as a new Fragment during the Activitys onCreate() method.
I know want to preserve my Fragments during configuration changes. Currently, when I change my screen orientation, all my currently Fragments are deleted, and I get back to the starting Fragment, naturally because the Activity is recreated, and the Fragment and the Adapater are reinstantiated during the onCreate() call. I was trying to save the state of the Adapter with the Adapter.saveInstance() during the Activitys onPause(), but when I try to restore it via Adapter.restoreInstance(), I get an empty adapter.
Can anyone give me a hint on what is the correct way in Android to save state a FragmentStatePagerAdapter?
To save the state of the current fragment, i think first of all you will have to check which fragment is currently added/visible in the container activity. Once you have that fragment, simply use onSaveInstanceState() method of the container activity to save the instance of the current fragment.
For code snippet please follow this link.

Iterate over all currently loaded fragments in a ViewPager

I have a ViewPager. It has Fragments. When those Fragments are created, they load data from the server. When the user selects a menu item, I want to tell those fragments to filter their data without reloading from the server.
To do this, I have a subclass of FragmentPagerAdapter which keeps a List to hold a reference to each Fragment as it is created. When the menu item is selected, I simply iterate over that collection and call a method on each Fragment.
The problem arises when the device is rotated. The framework automatically restores the fragments to their parent view, without calling the getItem method of my adapter, meaning that my List is empty.
How can I either repopulate that List when the device is rotated, or obtain a list of all of the ViewPager's child Fragments without keeping a list?
EDIT: It may be important to note that my ViewPager lives in a Fragment, and that Fragment gets hot swapped via a side navigation menu. In other words, my ViewPager is not owned by an Activity, and there are some known issues about ViewPager not cleaning up its child fragments correctly which may be exacerbating the problem.
Check this link Get Current visible fragment in ViewPager
The author basically suggests 2 similar approaches which are to attach tags on fragment creation and keep track of it.
getSupportFragmentManager().beginTransaction().add(myFragment, "Some Tag").commit();
Then retrieve the tag like so:
int index = mViewPager.getCurrentItem();
String tag = mPageReferenceMap.get(index);
Fragment myFragment = getSupportFragmentManager().findFragmentByTag(tag);

Nested Fragments and ViewPager issues on Android

I am using a FragmentStatePagerAdapter in combination with a view pager, which is nested in a fragment on Android. Thus, I am using the ChildFragmentManager in combination with the FragmentStatePagerAdapter to create my fragments.
So far so good, but here is the problem:
If I open a different Activity without finishing the activity that hosts the fragment with the view pager and afterwards resume it, the fragment that was selected in the ViewPager is empty. If I switch the fragment in the ViewPager before I open the different Activity, this issue does not appear. After returning and seeing the empty Fragment in the ViewPager, I am still able to switch the next Fragments, but if I try to switch back to the empty Fragment, I get a NullPointerException. This issue does not occur if I switch between the Fragment hosting the ViewPager and a different Fragment or if I change orientations.
If I use the FragmentManager instead of the ChildFragmentManager, I do not have this issue when switching to a different Activity, but it will then occur if I switch between the hosting and a different fragment or if I change the orientation.
So here's what I already tried without any success:
* Use FragmentStatePagerAdapter adapter and FragmentPagerAdapter
* Use setRetainedInstance(true and false)
* Use getChildFragmentManager() and getFragmentManager()
* Override getItemPosition() return POSTION_NONE and use notifyDataChanged() in onResume()
The only thing that is currently doing the trick is recreating the PagerAdapter in onResume() and re-initializing the ViewPager, but I think that's really bad practice as everything needs to be recreated.
So is there somebody, who can explain to me how a correct implementation should look like, or why the fragments can become empty (they are not null, I checked that). I am searching for a more elegant solution rather than recreating everything each time I resume my activity.
Any help is really appreciated.

Fragment with fragments inside - retain state

I have one fragment that contains two fragments inside.
Every fragment is loading some names from database and displays them as a list with a limit of 50.
At start my adapter has 50 elements, when user scrolls down another 50 is beign loaded, then adapter is with 100 elements.
Now whenever I rotate the device, my data in adapter is messed up, that is my question is there any way to save my state of childFragment? without using parceable and parcel the whole 100 elements together with current position?
You should use Fragment's setRetainInstance(boolean) feature.
Setting
setRetainInstance(true);
to a Fragment containing the child Fragments should do.
Control whether a fragment instance is retained across Activity re-creation (such as from a configuration change). This can only be used with fragments not in the back stack. If set, the fragment lifecycle will be slightly different when an activity is recreated:
Understanding Fragment's setRetainInstance(boolean)

FragmentStatePagerAdapter performance issue

I have implemented an activity that displays fragments in a viewpager. The activity initially displays 5 fragments of a given type (type A). Each type A fragment contains a list of information. When a button is pressed, the fragments are replaced with another tpye of fragments, type B (i.e., fragments that use a different layout and display different information are loaded).
I have implemented this with a ViewPager and a custom FragmentStatePagerAdapter. The custom FragmentStatePagerAdapter overrides the getCount, instantiateItem, getItem, getItemPosition, etc. functions and all works fine. When I press the button the views switch from fragment type A to fragment type B. In order to do this I am using a replace fragment transaction and I also call notifyDataSetChanged on the adapter. The switch from type A to type B fragments is accomplished by checking which type of fragment I need to create in the adapter's getItem function. The problem is that the switching process (i.e., changing from fragment type A to fragment type B and vice versa) takes some time (around 2 seconds) - this delay is quite noticeable and annoying.
This occurs because the adapter's getItemPosition function returns POSITION_NONE. When POSITION_NONE is returned, the viewPager recreates the fragment. Furthermore, when the replace transaction is executed, all items of the adapter are removed and all new ones are recreated. The same happens when I switch back to fragments type A.
Does anyone know if there is a better or faster way to do this? Using a FragmentPagerAdapter should not be a good solution since the number of fragments in the viewPager could grow.
I have commented out the updating of the fragments and the problem is gone so the problem is the time it takes to update the fragments. Is there a way to update the fragments asynchronously? That should take care of the problem.
The ViewPager instatiates by default a minimun count of Fragments. In general the left and right one of the current Fragment. So you don't need to care about the total number of Fragments.
You can control the total number with the ViewPager.setOffScreenPageLimit() method.
Also a AsyncTask seems to be a good idea to manage the intensiv work of your Fragments.

Categories

Resources