Handle Fragment duplication on Screen Rotate (with sample code) - android

There are some similar answers, but not to this situation.
My situation is simple.
I have an Activity with two different layouts, one in Portrait, another in Landscape.
In Portrait, i use <FrameLayout> and add Fragment into it dynamically.
In Landscape, i use <fragment> so the Fragment is static. (in fact this doesn't matter)
It first starts in Portrait, then i added the Fragment by simply:
ListFrag listFrag = new ListFrag();
getSupportFragmentManager().beginTransaction()
.replace(R.id.FragmentContainer, listFrag).commit();
where ListFrag extends ListFragment.
Then i do a screen rotate. I found the listFrag is re-creating in the Landscape mode.
(In which i noticed the onCreate() method is called again with a non-null Bundle)
i tried to use setRetainInstance(false) like #NPike said in this post. But the getRetainInstance() is already false by default. It does not do what i expected as the docs said. Could anyone please explain?
The fragment i am dealing with, is a ListFragment, which does setListAdapter() in onCreate(). So the if (container == null) return null; method cannot be used here. (or i dont know how to apply).
I got some hints from this post. Should i use if (bundle != null) setListAdapter(null); else setListAdapter(new ...); in my ListFragment? But is there a nicer way to indeed removing/deleting the fragment when it is destroyed/detached, rather than doing it in its creation time? (so as the if (container == null) return null; method)
Edit:
The only neat way i found is doing getSupportFragmentManager().beginTransaction().remove(getSupportFragmentManager().findFragmentById(R.id.FragmentContainer)).commit(); in onSaveInstanceState(). But it will raise another problems.
When screen is partially obscured, like WhatsApp or TXT dialogue boxes pop up, the fragment will be disappeared also. (this is relatively minor, just visual issue)
When screen rotate, the Activity is completely destroyed and re-created. So i can re-add the fragment in onCreate(Bundle) or onRestoreInstanceState(Bundle). But in the case of (1), as well as switching Activities, neither onCreate(Bundle) nor onRestoreInstanceState(Bundle) will be called when user get back to my Activity. I have nowhere to recreate the Activity (and retrieve data from Bundle).
Sorry I didn't say it clearly that, i already have a decision making, which the getSupportFragmentManager()...replace(...).commit(); line only run in Portrait mode.
Example code
I have extracted the simple code, for better illustration of the situration :)
MainActivity.java
package com.example.fragremovetrial;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
public class MainActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (findViewById(R.id.FragmentContainer) != null) {
System.out.println("-- Portrait --"); // Portrait
ListFrag listFrag = new ListFrag();
getSupportFragmentManager().beginTransaction()
.replace(R.id.FragmentContainer, listFrag).commit();
} else {
System.out.println("-- Landscape --"); // Landscape
}
}
#Override
protected void onResume() {
super.onResume();
if (findViewById(R.id.FragmentContainer) != null) {
System.out.println("getRetainInstance = " +
getSupportFragmentManager().findFragmentById(R.id.FragmentContainer).getRetainInstance());
}
}
}
layout/activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/FragmentContainer"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
layout-land/activity_main.xml (doesn't matter)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
</LinearLayout>
ListFrag.java
package com.example.fragremovetrial;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.widget.ArrayAdapter;
public class ListFrag extends ListFragment {
private String[] MenuItems = { "Content A", "Contnet B" };
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
System.out.println("ListFrag.onCreate(): " + (savedInstanceState == null ? null : savedInstanceState));
setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, MenuItems));
}
}
Notice i got the following
Debug messages
-- Portrait --
ListFrag.onCreate(): null
getRetainInstance = false
(rotate Port -> Land)
ListFrag.onCreate(): Bundle[{android:view_state=android.util.SparseArray#4052dd28}]
-- Landscape --
Previously focused view reported id 16908298 during save, but can't be found during restore.
(rotate Land -> Port)
ListFrag.onCreate(): Bundle[{android:view_state=android.util.SparseArray#405166c8}]
-- Portrait --
ListFrag.onCreate(): null
getRetainInstance = false
(rotate Port -> Land)
ListFrag.onCreate(): Bundle[{android:view_state=android.util.SparseArray#4050fb40}]
-- Landscape --
Previously focused view reported id 16908298 during save, but can't be found during restore.
(rotate Land -> Port)
ListFrag.onCreate(): Bundle[{android:view_state=android.util.SparseArray#40528c60}]
-- Portrait --
ListFrag.onCreate(): null
getRetainInstance = false
where the number of Fragment created will not increase infinitely as screen keep rotating, which i cannot explain. (please help)

The correct way to handle this is to put the following in your onCreate()
if (savedInstanceState == null) {
// Do fragment transaction.
}

I finally come up with a solution to prevent unwanted Fragment re-creating upon the Activity re-creates. It is like what i mentioned in the question:
The only neat way i found is doing getSupportFragmentManager().beginTransaction().remove(getSupportFragmentManager().findFragmentById(R.id.FragmentContainer)).commit(); in onSaveInstanceState(). But it will raise another problems...
... with some improvements.
In onSaveInstanceState():
#Override
protected void onSaveInstanceState(Bundle outState) {
if (isPortrait2Landscape()) {
remove_fragments();
}
super.onSaveInstanceState(outState);
}
private boolean isPortrait2Landscape() {
return isDevicePortrait() && (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
}
and the isDevicePortrait() would be like:
private boolean isDevicePortrait() {
return (findViewById(R.id.A_View_Only_In_Portrait) != null);
}
*Notice that we cannot use getResources().getConfiguration().orientation to determine if the device is currently literally Portrait. It is because the Resources object is changed RIGHT AFTER the screen rotates - EVEN BEFORE onSaveInstanceState() is called!!
If we do not want to use findViewById() to test orientation (for any reasons, and it's not so neat afterall), keep a global variable private int current_orientation; and initialise it by current_orientation = getResources().getConfiguration().orientation; in onCreate(). This seems neater. But we should be aware not to change it anywhere during the Activity lifecycle.
*Be sure we remove_fragments() before super.onSaveInstanceState().
(Because in my case, i remove the Fragments from the Layout, and from the Activity. If it is after super.onSaveInstanceState(), the Layout will already be saved into the Bundle. Then the Fragments will also be re-created after the Activity re-creates. ###)
### I have proved this phenomenon. But the reason of What to determine a Fragment restore upon Activity re-create? is just by my guess. If you have any ideas about it, please answer my another question.

In your onCreate() method you should only create your ListFrag if you are in portrait mode. You can do that by checking if the FrameLayout view that you only have in the portrait layout is not null.
if (findViewById(R.id.yourFrameLayout) != null) {
// you are in portrait mode
ListFrag listFrag = new ListFrag();
getSupportFragmentManager().beginTransaction()
.replace(R.id.FragmentContainer, listFrag).commit();
} else {
// you are in landscape mode
// get your Fragment from the xml
}
In the end if you switch from portrait to landscape layout, you don't want to have another ListFrag created, but use the Fragment you have specified in your xml.

#midnite ,first of all thanks for your question, I had the same question, on wich I worked for days. Now I wound some tricky resolution to this problem - and want to share this to community.
But If someone has better solution, please write in comments.
So, I have same situation - different layouts for two device orientation. In portrait there is no need for DetailsFragment.
I simply in OnCreate trying to find already created fragments:
fragment = (ToDoListFragment) getFragmentManager().findFragmentByTag(LISTFRAGMENT);
frameDetailsFragment = (FrameLayout) findViewById(R.id.detailsFragment);
detailsFragment = (DetailsFragment) getFragmentManager().findFragmentByTag(DETAILS_FRAGMENT);
settingsFragment = (SettingsFragment) getFragmentManager().findFragmentByTag(SETTINGS_FRAGMENT);
Right after that I am adding my main fragment -
if (fragment == null){
fragment = new ToDoListFragment();
getFragmentManager().beginTransaction()
.add(R.id.container, fragment, LISTFRAGMENT)
.commit();
}
And clear back stask of my fragments:
if (getFragmentManager().getBackStackEntryCount() > 0 ) {
getFragmentManager().popBackStackImmediate();
}
And the MOST interesting is here -
destroyTmpFragments();
Here is the method itself:
private void destroyTmpFragments(){
if (detailsFragment != null && !detailsFragment.isVisible()) {
Log.d("ANT", "detailsFragment != null, Destroying");
getFragmentManager().beginTransaction()
.remove(detailsFragment)
.commit();
detailsFragment = null;
}
if (settingsFragment != null && !settingsFragment.isVisible()) {
Log.d("ANT", "settingsFragment != null, Destroying");
getFragmentManager().beginTransaction()
.remove(settingsFragment)
.commit();
settingsFragment = null;
}
}
As you can see, I clean manually all fragments, that FragmentManager gentfully saved for me (great thanks to him).
In log I have next lifecycle calls:
04-24 23:03:27.164 3204 3204 D ANT MainActivity onCreate()
04-24 23:03:27.184 3204 3204 I ANT DetailsFragment :: onCreateView
04-24 23:03:27.204 3204 3204 I ANT DetailsFragment :: onActivityCreated
04-24 23:03:27.204 3204 3204 I ANT DetailsFragment :: onDestroy
04-24 23:03:27.208 3204 3204 I ANT DetailsFragment :: onDetach
So in onActivityCreated make your views check for null - in case fragment is not visible. It will be deleted little bit later (It is so maybe cuz fragment manager's remove is async)
After, in activity's code we can create brand new Fragment instance, with proper layout (fargmnet's placeholder) and fragment will be able to find it's views for example, and will not produce NullPointerException
But, fragments that are in back stack are deleted pretty fast, without call to onActivityCreated (with th help of above code:
if (getFragmentManager().getBackStackEntryCount() > 0 ) {
getFragmentManager().popBackStackImmediate();
}
At last, at the end i add fragment if I am in land orientation -
if (frameDetailsFragment != null){
Log.i("ANT", "frameDetailsFragment != null");
if (EntryPool.getPool().getEntries().size() > 0) {
if (detailsFragment == null) {
detailsFragment = DetailsFragment.newInstance(EntryPool.getPool().getEntries().get(0), 0);
}
getFragmentManager().beginTransaction()
.replace(R.id.detailsFragment, detailsFragment, DETAILS_FRAGMENT)
.commit();
}
}

Related

save value of a variable in a DialogFragment when the screen rotates

Well, I wanted to save value of a variable contained in a dialogFragment when the screen is rotated in Android. I've tried every method I could find on the internet, and none of them has worked for me. Some kill my application, and others simply were not doing anything.
I need a real and effective way to save the value of an EditText that is reset when the device screen rotates. The EditText is in a DialogFragment turn this into a FragmentActivity.
thank you very much
Set your fragment's retaingInstance flag to true:
http://developer.android.com/reference/android/app/Fragment.html#setRetainInstance(boolean)
This prevents Fragment instance from being recreated.
Also be sure you don't recreate the fragment all the time:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
if (savedInstanceState == null) {
Fragment f = new Myfragment();
f.setRetainInstance(true);
getSupportFragmentManager().beginTransaction()
.add(R.id.container, f))
.commit();
}
}
Since View state is preserved during Activity recreation and your are keeping the same Fragment instance you don't need to save TextView value all the time.
I don't know if I understood your question, but you can capture the rotation as follows:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT)
{
//save value
}
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
{
//save value
}
}
If you want that your activity don't restart, you should add this into the manifest file:
<activity
.....
android:configChanges="keyboardHidden|orientation|screenSize"
..... >
</activity>
I just found out that you can not apply the methods to save bundles automatically to the dialogues, but these would apply to activities or fragments of these dialogues dependent. If I can fix it by code, will put the solution here. thank you

can I rely on savedInstanceState != null for adding fragment to layout

android developer tutorial (code beloew) only adds fragment to layout when savedInstanceState != null.
That indicates when savedInstanceState == null fragment is always not added to layout, and when savedInstanceState != null fragment is always added to layout.
Why can I rely on it? I can not find a direct relationship with savedInstanceState and if a fragment is added to layout or not.
the code I am talking about:
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
public class MainActivity extends FragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.news_articles);
if (findViewById(R.id.fragment_container) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
// *** question: I don't understand the comment above. (described in my question)
if (savedInstanceState != null) {
return;
}
HeadlinesFragment firstFragment = new HeadlinesFragment();
firstFragment.setArguments(getIntent().getExtras());
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, firstFragment).commit();
}
}
}
Fragments are attached to activity automatically. You don't need to add it again if you add it ones. Android will do it by itself.
If savedInstanceState bundle is not null in onCreate then your Activity was recreated(maybe you change orientation or Android killed your application because of low memmory) and you don't need to attach fragment again.
Of course this depend on different situation. There are cases when you need to add different Fragments in onCreate every time Activity change orientation. Then you don't need to use that check.

Restoring Fragment state after configuration change if Activity layout changes

My Activity has a one-pane layout in portrait and a two-pane layout in landscape, using Fragments. I'd like the system to restore all the views after an orientation change, but I don't know where to start.
Is this even possible considering the layout is different (but similar) in the two orientations?
If anyone has implemented this (or at least tried), please share you experience.
Maybe I know what the problem is. Hope my answer helps someone want to solve such problem.
In case there are a Fragment in your Activity, you config that Activity in AndroidManifest.xml with
android:configChanges="keyboardHidden|orientation|screenSize"
then, you want to change the layout of the Activity when onConfigurationChanged triggered. Once the Activity inflate a new layout or using setContentView(R.layout.new_layout);, the fragment will disappear, however, that fragment still running and just disappear from the view.
So the problem is that fragment is attached to the previous layout, what you need to do:
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
if (fm.findFragmentById(R.id.pane_list) == null) {
// instantiate fragment and add to view
mFragment = new ItemFragment();
transaction.add(R.id.pane_list, mFragment );
} else {
// fragment already exists, we re-attahced it
mFragment = fm.findFragmentById(R.id.pane_list);
transaction.detach(mFragment);
transaction.attach(mFragment);
}
transaction.commit();
After detached from old layout and attached to new layout, problem solved.
Correct me if there any wrong :)
I urge you to use a Fragment with setRetainInstance(true) in its onCreate method. This makes the fragment retain its member variables across Activity configuration changes. Please read this blog post which explains the information you need:
http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("curChoice", mCurCheckPosition);
}
Which you can use later like this:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
// Restore last state for checked position.
mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
}
}

After orientation change, optionsmenu of fragment doesn't disappear

I implemented my layout based on this tutorial: http://android-developers.blogspot.hu/2011/02/android-30-fragments-api.html
The differences are:
I have different fragments to show, based on the choice in the left
list
The "details fragments" (those that come to the right) have different options menus
My problem is that if I have already selected something from the left and then rotate the phone to portrait, the last optionsmenu is still there and is visible.
I think the problem comes from the last active "details" fragment is recreated after the orientation change. to test it I created these two methods:
#Override
public void onStart() {
super.onStart();
setHasOptionsMenu(true);
}
#Override
public void onStop() {
super.onStop();
setHasOptionsMenu(false);
}
And I'm showing the right fragment like this:
case R.id.prefs_medicines:
if (mDualPane) {
// Check what fragment is shown, replace if needed.
View prefsFrame = getActivity().findViewById(R.id.preferences);
if (prefsFrame != null) {
// Make new fragment to show this selection.
MedicineListF prefF = new MedicineListF();
// Execute a transaction, replacing any existing
// fragment with this one inside the frame.
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.preferences, prefF);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
} else {
// Otherwise we need to launch a new activity to display
// the dialog fragment with selected text.
Intent intent = new Intent();
intent.setClass(getActivity(), MedicinePrefsActivity.class);
startActivity(intent);
}
break;
in one of my "details" fragment. when I debugged it, the onstart was called after the rotation.
The problem in pictures:
1: in landscape it's OK
Landscape mode http://img834.imageshack.us/img834/8918/error1d.png
2: in portrait: optionsmenu not needed
Portrait mode http://img860.imageshack.us/img860/8636/error2r.png
How can I get rid of the optionsmenu in portrait mode?
I had the same problem, and resolved it by setting setHasOptionsMenu(true) in the fragment only when savedInstanceState is null. If onCreate gets a bundle then the fragment is being restored in an orientation change to portrait, so don't display the menu.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState == null) {
setHasOptionsMenu(true);
}
}

Fragment gets initialized twice when reloading activity with tabs when orientation changes

I have a problem reloading an activity with tabs and fragments when I change the orientation of my device.
Here's the situation:
I have an activity which has 3 tabs in the action bar. Each tab loads a different fragment in a FrameLayout in main view. Everything works fine if I don't change the orientation of the device. But when I do that Android tries to initialize the currently selected fragment twice which produce the following error:
E/AndroidRuntime(2022): Caused by: android.view.InflateException: Binary XML file line #39: Error inflating class fragment
Here's the sequence of steps that produce the error:
I load the activity, select tab nr 2. and change the orientation of the device.
Android destroys the activity and the instance of the fragment loaded by tab nr 2 (from now on, 'Fragment 2'). Then it proceeds to create new instances of the activity and the fragment.
Inside Activity.onCreate() I add the first tab to the action bar. When I do that, this tab gets automatically selected. It may represent a problem in the future, but I don't mind about that now. onTabSelected gets called and a new instance of the first fragment is created and loaded (see code below).
I add all the other tabs without any event being triggered, which is fine.
I call ActionBar.selectTab(myTab) to select Tab nr 2.
onTabUnselected() gets called for the first tab, and then onTabSelected() for the second tab. This sequence replaces the current fragment for an instance of Fragment 2 (see code below).
Next, Fragment.onCreateView() is called on Fragment 2 instance and the fragment layout gets inflated.
Here is the problem. Android Calls onCreate() and then onCreateView() on the fragment instance ONCE AGAIN, which produces the exception when I try to inflate (a second time) the layout.
Obviously the problem is Android is initializing the fragment twice, but I don't know why.
I tried NOT selecting the second tab when I reaload the activity but the second fragment gets initialized anyway and it is not shown (since I didn't select its tab).
I found this question: Android Fragments recreated on orientation change
The user asks basically the same I do, but I don't like the chosen answer (it's only a workaroud). There must be some way to get this working without the android:configChanges trick.
In case it's not clear, what I want to know how whether to prevent the recreation of the fragment or to avoid the double initialization of it. It would be nice to know why is this happening also. :P
Here is the relevant code:
public class MyActivity extends Activity implements ActionBar.TabListener {
private static final String TAG_FRAGMENT_1 = "frag1";
private static final String TAG_FRAGMENT_2 = "frag2";
private static final String TAG_FRAGMENT_3 = "frag3";
Fragment frag1;
Fragment frag2;
Fragment frag3;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// my_layout contains a FragmentLayout inside
setContentView(R.layout.my_layout);
// Get a reference to the fragments created automatically by Android
// when reloading the activity
FragmentManager fm = getFragmentManager();
this.frag1 = fm.findFragmentByTag(MyActivity.TAG_FRAGMENT_1);
this.frag2 = fm.findFragmentByTag(MyActivity.TAG_FRAGMENT_2);
this.frag3 = fm.findFragmentByTag(MyActivity.TAG_FRAGMENT_3)
ActionBar actionBar = getActionBar();
// snip...
// This triggers onTabSelected for the first tab
actionBar.addTab(actionBar.newTab()
.setText("Tab1").setTabListener(this)
.setTag(MyActivity.TAG_FRAGMENT_1));
actionBar.addTab(actionBar.newTab()
.setText("Tab2").setTabListener(this)
.setTag(MyActivity.TAG_FRAGMENT_2));
actionBar.addTab(actionBar.newTab()
.setText("Tab3").setTabListener(this)
.setTag(MyActivity.TAG_FRAGMENT_3));
Tab t = null;
// here I get a reference to the tab that must be selected
// snip...
// This triggers onTabUnselected/onTabSelected
ab.selectTab(t);
}
#Override
protected void onDestroy() {
// Not sure if this is necessary
this.frag1 = null;
this.frag2 = null;
this.frag3 = null;
super.onDestroy();
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Fragment curFrag = getFragmentInstanceForTag(tab.getTag().toString());
if (curFrag == null) {
curFrag = createFragmentInstanceForTag(tab.getTag().toString());
if(curFrag == null) {
// snip...
return;
}
}
ft.replace(R.id.fragment_container, curFrag, tab.getTag().toString());
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft)
{
Fragment curFrag = getFragmentInstanceForTag(tab.getTag().toString());
if (curFrag == null) {
// snip...
return;
}
ft.remove(curFrag);
}
private Fragment getFragmentInstanceForTag(String tag)
{
// Returns this.frag1, this.frag2 or this.frag3
// depending on which tag was passed as parameter
}
private Fragment createFragmentInstanceForTag(String tag)
{
// Returns a new instance of the fragment requested by tag
// and assigns it to this.frag1, this.frag2 or this.frag3
}
}
The code for the Fragment is irrelevant, it just returns an inflated view on onCreateView() method override.
I got a simple answer for that:
Just add setRetainInstance(true); to the Fragment's onAttach(Activity activity) or onActivityCreated(Bundle savedInstanceState).
These two are call-backs in the Fragment Class.
So basically, what setRetainInstance(true) does is:
It maintains the state of your fragment as it is, when it goes through:
onPause();
onStop();
It maintains the instance of the Fragment no matter what the Activity goes through.
The problem with it could be, if there are too many Fragments, it may put a strain on the System.
Hope it helps.
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
setRetainInstance(true);
}
Open for Correction as always. Regards, Edward Quixote.
It seems that, when the screen is rotated and the app restarted, it is recreating each Fragment by calling the default constructor for the Fragment's class.
I have encountered the same issue and used the following workaround:
in the fragment's onCreateView begining of:
if (mView != null) {
// Log.w(TAG, "Fragment initialized again");
((ViewGroup) mView.getParent()).removeView(mView);
return mView;
}
// normal onCreateView
mView = inflater.inflate(R.layout...)
I think this is a fool proof way to avoid re-inflating of the root view of the fragment:
private WeakReference<View> mRootView;
private LayoutInflater mInflater;
/**
* inflate the fragment layout , or use a previous one if already stored <br/>
* WARNING: do not use in any function other than onCreateView
* */
private View inflateRootView() {
View rootView = mRootView == null ? null : mRootView.get();
if (rootView != null) {
final ViewParent parent = rootView.getParent();
if (parent != null && parent instanceof ViewGroup)
((ViewGroup) parent).removeView(rootView);
return rootView;
}
rootView = mFadingHelper.createView(mInflater);
mRootView = new WeakReference<View>(rootView);
return rootView;
}
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
mInflater=inflater!=null?inflater:LayoutInflater.from(getActivity());
final View view = inflateRootView();
... //update your data on the views if needed
}
add
android:configChanges="orientation|screenSize"
in the manifest file
To protect activity recreate try to add configChanges in your Activity tag (in manifest), like:
android:configChanges="keyboardHidden|orientation|screenSize"
My code was a little different, but I believe our problem is the same.
In the onTabSelected I didn't use replace, I use add when is the first time creating the fragment and attach if isn't. In the onTabUnselected I use detach.
The problem is that when the view is destroyed, my Fragment was attached to the FragmentManager and never destroyed. To solve that I implemented on the onSaveInstanceBundle to detach the fragment from the FragmentManager.
The code was something like that:
FragmentTransition ft = getSupportFragmentManager().begin();
ft.detach(myFragment);
ft.commit();
In the first try I put that code in the onDestroy, but I get a exception telling me that I couldn't do it after the onSaveInstanceBundle, so I moved the code to the onSaveInstanceBundle and everything worked.
Sorry but the place where I work don't allow me to put the code here on StackOverflow. This is what I remember from the code. Feel free to edit the answer to add the code.
I think you are facing what I faced. I had a thread downloader for json which starts in onCreate() , each time I changed the orientation the thread is called and download is fired. I fixed this using onSaveInstance() and onRestoreInstance() to pass the json response in a list, in combination of checking if the list is not empty, so the extra download is not needed.
I hope this gives you a hint.
I solved this problem by using below code.
private void loadFragment(){
LogUtil.l(TAG,"loadFragment",true);
fm = getSupportFragmentManager();
Fragment hf = fm.findFragmentByTag("HOME");
Fragment sf = fm.findFragmentByTag("SETTING");
if(hf==null) {
homeFragment = getHomeFragment();// new HomeFragment();
settingsFragment = getSettingsFragment();// new Fragment();
fm.beginTransaction().add(R.id.fm_place, settingsFragment, "SETTING").hide(settingsFragment).commit();
fm.beginTransaction().add(R.id.fm_place, homeFragment, "HOME").commit();
activeFragment = homeFragment;
}else{
homeFragment = hf;
settingsFragment = sf;
activeFragment = sf;
}
}
Initiate this method in OnCreate();

Categories

Resources