Reputation: 1168
I am not going to list every reference I've read through before posting this, but I have extensively read similar questions on stackoverflow and all of the android developer docs on activity/fragment lifecycles and maintaining state and have not found a solution.
Here is my scenario:
I have a main activity (ImpulseActivity) that uses a FragmentPagerAdapter. Each fragment displays a separate list of data that I am retrieving from the server. When pressing an action_item in ImpulseActivity's actionbar, you can filter data sent from the server. To accomplish this, ImpulseActivity launches a separate activity (FilterEventsActivity). FilterEventsActivity lists ImpulseActivity as it's parent activity. When pressing the back button on FilterEventsActivity, ImpulseActivity is recreated (OnCreate called) with a null (Bundle savedInstanceState). For testing purposes, I am overriding OnSaveInstanceState and placing fake data in outState. Note that this happens for every activity launched from ImpulseActivity.
My question is:
What is the proper design paradigm to prevent each fragment from needing to reload data in this particular situation? I would prefer not to use the Singleton pattern since my fragments are reused in other activities.
Relevant source code if needed:
public class ImpulseActivity extends FragmentActivity implements
ActionBar.TabListener {
private MapSearchFragment mSearchFragment;
private BulletinFragment mBulletinFragment;
SectionsPagerAdapter mSectionsPagerAdapter;
ViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.impulse_activity);
Log.v("ImpulseActivity", "onCreate " + savedInstanceState);
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
CategoryManager manager = CategoryManager.getManager();
manager.setListener(this);
manager.loadCategories();
mSectionsPagerAdapter = new SectionsPagerAdapter(
getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
mViewPager
.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
actionBar.addTab(actionBar.newTab()
.setText(mSectionsPagerAdapter.getPageTitle(i))
.setTabListener(this));
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putDouble("Hello", 1.02);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.impulse_activity_actions, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_create) {
return true;
}
if (id == R.id.action_filter) {
Intent intent = new Intent(this, FilterEventsActivity.class);
startActivity(intent);
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
int position = tab.getPosition();
mViewPager.setCurrentItem(position, true);
}
@Override
public void onEventListClick(Event e) {
Intent mIntent = new Intent(this, EventActivity.class);
Bundle mBundle = new Bundle();
mBundle.putSerializable(EventDetailsFragment.Event_Key, e);
mIntent.putExtras(mBundle);
startActivity(mIntent);
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
Fragment fragment;
switch(position) {
case 0:
if (mBulletinFragment != null) {
fragment = mBulletinFragment;
} else {
fragment = new BulletinFragment();
mBulletinFragment = (BulletinFragment) fragment;
}
break;
case 1:
fragment = new MapSearchFragment();
mSearchFragment = (MapSearchFragment) fragment;
break;
case 2:
fragment = new MyEventsFragment();
break;
default:
fragment = new BulletinFragment();
break;
}
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
@Override
public int getCount() {
// Show 3 total pages.
return 3;
}
@Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
switch (position) {
case 0:
return "Bulletin";
case 1:
return "Map";
case 2:
return "My Events";
default:
return "Test";
}
}
}
}
AndroidManifest.xml
<activity
android:name=".Home.ImpulseActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".Event.EventActivity"
android:label="@string/title_activity_event"
android:parentActivityName=".Home.ImpulseActivity" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".Home.ImpulseActivity" />
</activity>
Upvotes: 3
Views: 891
Reputation: 55350
Although the question mentions Fragments, the problem is actually with up navigation.
The default implementation for up navigation doesn't work exactly as one would expect for standard activties. In particular, when the parent activity has launchMode="standard"
(the default), pressing the up button will create a new instance of it, not return to the previous one.
There are two alternatives for solving this problem:
launchMode
of ImpulseActivity
to singleTop
in the Manifest.Overriding the home button action to launch the intent with the FLAG_ACTIVITY_CLEAR_TOP
flag. For example, in EventActivity.onOptionsItemSelected()
:
if (id == android.R.id.home)
{
Intent intent = NavUtils.getParentActivityIntent(this);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
NavUtils.navigateUpTo(this, intent);
return true;
}
Either of these will bring your old activity to the top of the stack.
Upvotes: 6
Reputation: 82
if your fragments have layout just like activity example mainlayout.xml you can use intent for open each fragment with same details and dont use onstop(); pack create intent and intent flags in the main fragment activity
Upvotes: -1