Activity A has fragments. When it starts an intent to activity B, then when B.finish()
, A executes onCreate()
again.
But this time, even though A.onCreate()
has a new PacksPagerAdapter
and a new ViewPager
, the fragments are shown with old data.
I can see that that onCreateView()
is executed for each fragment, but it still has the old arguments since the static newInstance()
wasn't called. Arguments are created when FragmentPagerAdapter's getItem(position)
is called.
Here's how it's implemented -
public class PackActivity extends Activity {
...
PacksPagerAdapter mPacksPagerAdapter;
ViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPacksPagerAdapter = new MyPagerAdapter(getFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mPacksPagerAdapter);
mViewPager.setOffscreenPageLimit(PACK_PAGES - 1);
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
actionBar.setTitle(...);
}
});
}
...
}
public class MyPagerAdapter extends FragmentPagerAdapter {
...
@Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class
// below).
return PackFragment.newInstance(myData);
}
...
}
public class PackFragment extends Fragment {
...
public static PackFragment newInstance(PackInfo pack) {
PackFragment fragment = new PackFragment();
Bundle bdl = new Bundle(2);
bdl.putSerializable(EXTRA_PACK, pack);
bdl.putInt(EXTRA_PACK_POSITION, pack.packNumber);
fragment.setArguments(bdl);
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View packView = inflater.inflate(R.layout.pack_fragment, container, false);
// this has the old argument, since newInstance(...) wasn't called
PackInfo pack = (PackInfo) getArguments().getSerializable(EXTRA_PACK);
...
return packView;
}
...
}
Any idea why new fragments aren't being instantiated on the 2nd creation of activity A?
The answer is, as Tal said, is that activity is being restored, so old fragments are being reattached instead of creating new ones.
After spending a lot of time studying this, I've found that there are typically 3 scenarios for activity-fragments lifecycle. Here are the scenarios, the lifecycle and how to reload fragment's old data:
New activity
Lifecycle: onCreate() ==> onResume() ==> Fragments are created and attached
No need to reload.
Restored activity
Lifecycle: onCreate() ==> Fragments inflated with old data and reattached ==> onResume()
In onResume(), remove all fragments and create new ones, either manually or automatically using an adapter -
// Remove all fragments
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
for (int i = BuildConfig.PACK_PAGES - 1; i >= 0; i--) {
Fragment f = findFragmentByPosition(i);
if (f != null)
fragmentTransaction.remove(f);
}
fragmentTransaction.commit();
// This will force recreation of all fragments
viewPager.setAdapter(packsPagerAdapter);
Resumed activity
Lifecycle: onResume()
Same as activity restore, remove old fragments and recreate.
Note: Some OS versions always restores activity, even when opening a SettingsActivity for a few seconds, and other (older) versions will always resume.
my answer will be better if you'll post the fragment transaction you commit in activity A.
not sure that you know it or not - if Activity A is re-created when it pop back from back stack - it means that it restored from previous instance state.
in that case, you should not perform the transaction again, because - it already happens automatically via the super.onCreate() Activity method. in fact, if you'll perform the fragment trasaction in that case - you'll cause the same fragment to be added twice (2 instances)
you can know if currently onCreate()
been called from restoring instance state by checking if savedInstanceState
parameter is null or not.
my assumption is that you are not checking savedInstanceState
, and performing the transaction anyway.
if I'm right, then the following change should fix the fragment duplication problem:
instead of:
public static class ActivityA extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
performFragmentTransaction();
}
write:
public static class ActivityA extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
performFragmentTransaction();
}
}
more info at - http://developer.android.com/guide/components/fragments.html