Reputation: 16221
I am having a problem with Fragments
and orientation change.
I have an application which has a MainActivity
which handles the switching up Fragments
via a tabbed action bar. Here is the code for the tabbed action bar and when a tab is selected.
private class MyTabListener <T extends android.support.v4.app.Fragment> implements ActionBar.TabListener {
private android.support.v4.app.Fragment mFragment;
private final Activity mActivity;
private final String mTag;
private final Class<T> mClass;
public MyTabListener(SherlockFragmentActivity activity, String tag, Class<T> clz) {
mActivity = activity;
mTag = tag;
mClass = clz;
}
@Override
public void onTabSelected(Tab tab, android.support.v4.app.FragmentTransaction ft) {
if (mFragment == null){ // check to see if the fragment has already been initialised. If not create a new one.
mFragment = android.support.v4.app.Fragment.instantiate(mActivity, mClass.getName());
ft.add(android.R.id.content,mFragment,mTag);
} else {
ft.attach(mFragment); // if the fragment has been initialised attach it to the current activity
}
}
@Override
public void onTabUnselected(Tab tab, android.support.v4.app.FragmentTransaction ft) {
if (mFragment != null){
ft.detach(mFragment); // when a fragment is no longer needed, detach it from the activity but dont destroy it
}
}
@Override
public void onTabReselected(Tab tab, android.support.v4.app.FragmentTransaction ft) {
}
The way I see it is that everything works fine when the application first loads in portrait mode. When I rotate, for some reason another instance of Fragment1
is added and then isn't detached when another tab is selected. This is also the case when I then rotate back to portrait.
I have tried using setRetainInstance(true);
in my Fragments
but this doesn't work.
Is there a method I need to override or do something with my Fragments
before rotating?
Thanks in advance.
EDIT I have now seen that onTabSelected is called again when the activity is recreated. Could this be the cause of my problem with fragments being attached more than once?
Here is my activities onCreate method.
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
//setContentView(R.layout.main);
}
// Create the Action Bar with tabs
ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
actionBar.setDisplayShowTitleEnabled(false);
//create the tab for track and add it to the action bar.
Tab tab = actionBar.newTab()
.setText("Track")
.setTabListener(new MyTabListener<TrackingFragment>(this,"track",TrackingFragment.class));
actionBar.addTab(tab);
//create the tab for ski tracks and add it to the action bar.
tab = actionBar.newTab()
.setText("Something Tracks")
.setTabListener(new MyTabListener<TrackListFragment>(this,"somethingtracks",TrackListFragment.class));
actionBar.addTab(tab);
//create the tab for photos and add it to the action bar.
tab = actionBar.newTab()
.setText("Photos")
.setTabListener(new MyTabListener<PhotoFragment>(this,"photos",PhotoFragment.class));
actionBar.addTab(tab);
Upvotes: 14
Views: 15472
Reputation: 2170
I had more or less the same problem, but the solutions presented above did not seem to work out in my situation. Eventually I found the following solution:
@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if (mFragment == null) {
mFragment = Fragment.instantiate(mActivity, mClass.getName());
ft.replace(android.R.id.content, mFragment, mTag); // Use replace iso add
}
else {
ft.attach(mFragment);
}
}
Upvotes: 1
Reputation: 1536
if(savedInstanceState == null) is not working always. sometimes savedInstanceState != null while you need to add another fragment because of landscape orientation.
Another approach is to test whether fm.findFragmentById(R.id.frameLayoutLeft), no matter what the orientation is, is null or not, if so, than create a new fragment instance otherwise do nothing. If you need a second fragment in landscape mode, you need first check whether it's landscape or not if so, check whether fm.findFragmentById(R.id.frameLayoutRight) is null or not. if null, than create, otherwise do nothing because it's already there retained by Android OS.
Upvotes: 0
Reputation: 11875
I found out that setRetainInstance
is actually ignored and all fragments created by the android.support.v4.app.FragmentManager
are stored in onSaveInstanceState
and are recreated in onCreate
.
For me the solution was to bluntly delete the superfluously saved fragment: https://stackoverflow.com/a/13996054/341091
Upvotes: 2
Reputation: 16393
It sounds like you don't have something in your onCreate
method wrapped in a if(savedInstanceState == null)
, so you are creating another fragment in addition to the one being restored from the savedInstanceState bundle.
EDIT
Looking more closely at your code, I think I was wrong about the onCreate, your onTabSelected should handle it. I think your if (mFragment == null)
is always coming up null, because you don't try and find the fragment. Change that code section to:
@Override
public void onTabSelected(Tab tab, android.support.v4.app.FragmentTransaction ft) {
mFragment = mActivity.getSupportFragmentManager().findFragmentByTag(mTag); // add this
if (mFragment == null){ // check to see if the fragment has already been initialised. If not create a new one.
mFragment = android.support.v4.app.Fragment.instantiate(mActivity, mClass.getName());
ft.add(android.R.id.content,mFragment,mTag);
} else {
ft.attach(mFragment); // if the fragment has been initialised attach it to the current activity
}
}
Upvotes: 8
Reputation: 11514
Short fix:
In the onTabSelected
method, before using if (mFragment == null)
you need to try to get the fragment (using mFragment = getSupportFragmentManager().findFragmentByTag(mTag)
). You can also set this from the outside but I don't see you doing this.
Checking if(savedInstanceState == null)
on onCreate
could also solve this and I consider it a better approach though! :)
Upvotes: 16