Fragment on Screen Rotation - android

I have added a viewpager to an activity which contains two page.
In onCreate of activity I add fragments to a fragmentAdapter:
public void onCreate(Bundle savedInstanceState)
{
......
FragmentAdapter fragmentAdapter = new FragmentAdapter
(
getSupportFragmentManager(),
new Fragment[]{FragmentGame.builder(id), FragmentComments.builder(id)},
new String[]{getString(R.string.gameInfo), getString(R.string.comments)}
);
ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager);
viewPager.setAdapter(fragmentAdapter);
public static FragmentGame builder(long id)
{
FragmentGame fragmentGame = new FragmentGame();
// fragmentGame.id = id;
Bundle bundle = new Bundle();
bundle.putLong(Constants.EXTRA_ID, id);
fragmentGame.setArguments(bundle);
return fragmentGame;
}
First time that activity is created the onCreateView of fragment is called as it's expected.
The strange behaviour is when the screen is rotated for the first time the onCreateView of fragment is called twice but the second call only has the correct id and for the first call id is 0.
On second screen rotation, onCreateView is called three times and again only the last one has id.
By more screen rotation, onCreateView calls increase.
I found some related question about fragment and screen rotation but I can't figure out why this happens and how to do it the right way.
----- UPDATE ------
The ID problem is solved as I replaced bundle with direct value setting.

If you don't want to reload your fragment on orientation change, write following for the activity in which you are loading the fragment in manifest file.
<activity
android:name="your activity name"
android:configChanges="orientation|screenSize" // add this to your activity
android:label="#string/app_name">
</activity>

Every time you rotate your device you are creating a new fragment and adding it to the FragmentManager.
All of your previously created fragments are still in the FragmentManager therefore the count increases by one each time.
If you wish to retain a value in your fragment, you need to store it in the arguments otherwise any values it contains would be lost when the system re-creates the fragment.
public static FragmentGame builder(long id) {
Bundle args = new Bundle();
args.putInt("id", id);
fragmentGame f = new fragmentGame();
f.setArguments(args);
}
Rather than creating a new fragment, I suspect you really want to retrieve your previously created one when you rotate the device. use getSupportFragmentManager().findFragmentById() or getSupportFragmentManager().findFragmentByTag() to do this.
Edit: Extra code
// Add fragment to the manager
FragmentTransaction trans=getSupportFragmentManager().beginTransaction();
trans.add(f,"myTag");
trans.commit();
// retrieve the fragment
Fragment f= getSupportFragmentManager().findFragmentByTag("myTag");
Just attempt to retrieve the fragment, if the value is null, create a new fragment and add it to the manager otherwise use the retrieved one.

Related

How to transfer data from one activity to a fragment with Firebase?

Hey I was wondering how I could transfer data from one activity to a fragment using fire base. I have edit text in the activity class and a list view in the Fragment.
I would like to display the information throughout the app database so that other users can see and edit the information too.
I dont know if the IDE matters but passing information to a fragment is usually done with fragment arguments. You need to create a static "newInstance" method in your fragment that you can call from the activity and pass whatever info to the fragment through it. Something like this:
public static mListFragment newInstance(String fromActivity) {
mListFragment fragment = new mListFragment ();
Bundle args = new Bundle();
args.putString("STIRNG_FROM_ACTIVITY", fromActivity);
fragment.setArguments(args);
return fragment;
}
You can then call the method from the activity like this:
FragmentManager fm = getFragmentManager().beginTransaction();
mListFragment fragment = new mListFragment();
fragment = mListFragment.newInstance("info_to_send");
fragmentTransaction.add(R.id.fragments_frame, fragment);
From here you can even persist the info across device screen orientation changes..
Just use firebaseRef to setValue() and set the value from the edittext.
Add ValueListener on the fragment to get the same value from dataSnapshot.
:D
https://github.com/firebase/quickstart-java/tree/master/database/src/main/java/com/google/firebase/quickstart

Android Fragments sharing info ways

i have a internal discussion about what way is better to share info between fragments contents inside a controller activity. In a first classical way, you can set arguments when you are going to replace fragments as follows:
//Just now i'm inside Fragment 1 and i'll navigate to Fragment 2
Fragment newFragment = getFragmentManager().findFragmentByTag(Fragment2.TAG);
Bundle b = new Bundle();
b.putBoolean("test1", true);
// Create new fragment and transaction
if(newFragment==null)
newFragment = Fragment2.newInstance(b);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)//.setCustomAnimations(R.anim.enter_anim, R.anim.exit_anim)
.replace(R.id.fragment_place, newFragment, Fragment2.class.getName())
.addToBackStack(newFragment.getClass().getName())
.commit();
The newInstace method does as i meant above, so, with setArguments:
public static Fragment2 newInstance(Bundle arguments){
Fragment2 f = new Fragment2();
if(arguments != null){
f.setArguments(arguments);
}
return f;
}
But Fragment1 and Fragment2 they are both inside a ControllerActivity, so i can also think about a second way to share information obtained in Fragment1 towards Fragment2, through declaring attributes in the ControllerActivity, so i could do (declaring previously an object in the activity) as follows inside any fragment:
EDIT
public class ControllerActivity extends FragmentActivity{
int value = 5;
...
And then, inside my fragment:
((SplashActivity)getActivity()).value = 10; //i can assign or recover value when i desire
My question is what inconveniences would have doing as the second way.
Writing code using 2nd way is fast. But the problem is you have to cast the general Activity to the more specific SplashActivity in which the value variable exists. If you want to use the Fragment with another Activity, or you want a Fragment to be a general purpose UI component you have to use interface for passing the data.
As mentioned in comments, bellow links provide more details about interface/callback method:
android docs
video from slidenerd
Hope this answers your question.

Activity recreates Fragments on Orientation Change because reference is lost, how to avoid that?

I'm trying to learn Android Fragments and I have a very specific problem concerning Fragment management, because screen orientation screws up my implementation.
EDIT: Already solved my problem, see the "Update" below.
Short version:
Using static Fragments, if I change screen orientation, the reference to R.id.fragment is lost and the Activity re-creates the Fragment causing problems because another Fragment is still present on the Layout (because they're defined on the XML maybe).
Context:
I have a Master/Detail workflow using the default Eclipse template and I have a different type of Fragment for every tab on the ItemList. Ideally, what I want to do is switch between fragments, but I want to retain their current state without using the BackStack, since I want to navigate with the ItemList, and using the Back button to close the App.
I couldn't find any solutions for this specific problem and I tried with a lot of different approaches. Right now I'm using static fragments defined in the main Layout:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/item_detail_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ItemDetailActivity"
tools:ignore="MergeRootFrame" >
<fragment android:name="com.example.pintproject.DevicesFragment"
android:id="#+id/devices"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"
/>
<fragment android:name="com.example.pintproject.ItemDetailFragment"
android:id="#+id/detail"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"
/>
</FrameLayout>
In the ItemListActivity onCreate(), I look for the Fragments in the layout, and add them if they aren't created yet, and I hold a reference to the current active Detail Fragment so I can hide it / show the fragment I switch to.
I'm using hide/show instead of replace because replace destroys the Fragment:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_list);
if (findViewById(R.id.item_detail_container) != null) {
// The detail container view will be present only in the
// large-screen layouts (res/values-large and
// res/values-sw600dp). If this view is present, then the
// activity should be in two-pane mode.
mTwoPane = true;
// In two-pane mode, list items should be given the
// 'activated' state when touched.
((ItemListFragment) getSupportFragmentManager().findFragmentById(
R.id.item_list)).setActivateOnItemClick(true);
}
df = (DevicesFragment) getSupportFragmentManager().findFragmentById(R.id.devices);
if (df==null){
df = new DevicesFragment();
getSupportFragmentManager().beginTransaction().add(R.id.item_detail_container,df).commit();
getSupportFragmentManager().beginTransaction().hide(df).commit();
}
idf = (ItemDetailFragment) getSupportFragmentManager().findFragmentById(R.id.detail);
if (idf==null){
idf = new ItemDetailFragment();
getSupportFragmentManager().beginTransaction().add(R.id.item_detail_container,idf).commit();
getSupportFragmentManager().beginTransaction().hide(idf).commit();
}
mContent = df;
#Override
public void onItemSelected(String id) {
if (mTwoPane) {
// In two-pane mode, show the detail view in this activity by
// adding or replacing the detail fragment using a
// fragment transaction.
switch (Integer.valueOf(id)){
case 1:{
if (idf!=null){
getSupportFragmentManager().beginTransaction().hide(mContent).commit();
getSupportFragmentManager().beginTransaction().show(idf).commit();
mContent = idf;
}
}break;
case 2:{
if (df!=null){
getSupportFragmentManager().beginTransaction().hide(mContent).commit();
getSupportFragmentManager().beginTransaction().show(df).commit();
mContent = df;
}
}break;
}
} else {
// In single-pane mode, simply start the detail activity
// for the selected item ID.
Intent detailIntent = new Intent(this, ItemDetailActivity.class);
detailIntent.putExtra(ItemDetailFragment.ARG_ITEM_ID, id);
startActivity(detailIntent);
}
}
Problem:
With this approach, the Fragments hide/show without any problems and hold the status, but if I make an Orientation Change, they are destroyed and recreated again.
I know they are destroyed because I'm not using setRetainInstance(), but the problem is when I change orientation, the Activity loses the reference to the Fragment, and
df = (DevicesFragment) getSupportFragmentManager().findFragmentById(R.id.devices);
is null, so the program creates another Fragment. If I change the orientation again, not only the program re-creates two new Fragments, but two more Fragments are somehow added to the layout and they aren't even hidden, they are shown one above another.
If I use setRetainInstance(), the Fragment holds the state when Orientation is changed, but still, the activity reference to the Fragment is null, and creates a new Fragment above the existing one, having two of each Fragment.
Example:
I create Fragment A and Fragment B in Landscape orientation. Both work fine and I can switch between them.
I change orientation to Portrait, Fragment A and Fragment B are destroyed and a new Fragment A' and Fragment B' are created, still, they work fine.
I change orientation again to Landscape, Fragment A' and Fragment B' are destroyed, a new Fragment A'' and Fragment B'' are created, but the screen shows another Fragment A and Fragment B, both at the same time (one above another, let's call them residual), and these new A'' and B'' work fine but are shown above residual A and B.
From this point on, every time I change orientation, 2 new Fragments are added to the previous ones, but they don't even hold the previous state.
I hope the example is clear enough. I think the problem is the Activity not holding view references when the orientation is changed, creates them again and I don't really know how to work around that.
UPDATE:
I solved my problem by using findFragmentByTag instead of findFragmentById. Since I can now retrieve Fragment s already created, I have to add them to the container adding a specific tag to search for.
So my test code looks like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_list);
if (findViewById(R.id.item_detail_container) != null) {
// The detail container view will be present only in the
// large-screen layouts (res/values-large and
// res/values-sw600dp). If this view is present, then the
// activity should be in two-pane mode.
mTwoPane = true;
// In two-pane mode, list items should be given the
// 'activated' state when touched.
((ItemListFragment) getSupportFragmentManager().findFragmentById(
R.id.item_list)).setActivateOnItemClick(true);
}
df = (DevicesFragment) getSupportFragmentManager().findFragmentByTag("df");
idf = (ItemDetailFragment) getSupportFragmentManager().findFragmentByTag("idf");
if (savedInstanceState==null){
if (df==null){
df = new DevicesFragment();
getSupportFragmentManager().beginTransaction().add(R.id.item_detail_container,df, "df").commit();
getSupportFragmentManager().beginTransaction().hide(df).commit();
}
if (idf==null){
idf = new ItemDetailFragment();
getSupportFragmentManager().beginTransaction().add(R.id.item_detail_container,idf,"idf").commit();
getSupportFragmentManager().beginTransaction().hide(idf).commit();
}
} else {
Log.i("OUT","INSTANCE NOT NULL");
}
mContent = df;
}
This is fully functional, also have to setRetainInstance(true) for every Fragment and they hold their current state no matter how many times we change the orientation.
You must never hold a reference to the fragment. Instead. Whenever you need something from it, retrieve the reference for a short moment.
public ItemListFragment getItemListFragment() {
return ((ItemListFragment) getSupportFragmentManager().findFragmentById(
R.id.item_list));
}
Then, whenever you need to get data from it, use
final ItemListFragment listFragment = getItemListFragment();
if (listFragment != null) {
// do something
}
And avoid calling setters. You can define the setters, but it's a better practice to either pass an arguments when creating a Fragment or retrieve the data by getActivity() from the Fragment itself, as described below.
This is done because the Fragment lifecycle not always matches the Activity one.
If you ever have to call setter from Activity, don't forget to save the value in Fragment's onSaveInstanceState(), if needed.
So instead of calling
setActivateOnItemClick(true);
From Activity, do it from the Fragment.
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final YourActivity activity = (Activtity) getYourActivity();
setActivateOnItemClick(activity.isMultiPane());
}
This way when the Fragment is re-created after Activity onCreate() (only in which you handle the value setting), it will has always access to the value
And define isMultiPane method from Activity, of course
public boolean isMultiPane() {
return mTwoPane;
}
Since there are no answer yet, here is my opinion :
When your orientation changes, your fragment is being recreated and you loose your data, right ? I think this is exactly whete the "savedInstanceState" is made for :
Caution: Your activity will be destroyed and recreated each time the user rotates the screen. When the screen changes orientation, the system destroys and recreates the foreground activity because the screen configuration has changed and your activity might need to load alternative resources (such as the layout).
Here is a link that can explain you how to handle that recreation
Hope this is useful to you ! =)

Android ViewPager and Fragment serialization

I've an activity with two attributes:
private Fragment firstFragment;
private Fragment secondFragment;
In onCreate method:
adapter = new MyPagerAdapter(getSupportFragmentManager());
pager = (ViewPager) findViewById(R.id.pager);
pager.setAdapter(adapter);
pager.setOffscreenPageLimit(6);
pager.setSaveEnabled(true);
where MyPagerAdapter extends FragmentStatePagerAdapter class.
Into getItem() method:
#Override
public Fragment getItem(int position) {
Bundle args = new Bundle();
switch (position) {
case FIRST:
secondFragment = new FirstFragment();
secondFragment.setArguments(args);
return secondFragment;
case SECOND:
secondFragment = new SecondFragment();
secondFragment.setArguments(args);
return secondFragment;
}
}
and all works correctly.
But, when I change the screen orientation, the private attributes is set to null and I lost the reference of two fragments.
So i've tried to serialized this fragment with:
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
getSupportFragmentManager().putFragment(outState, FirstFragment.class.getName(), firstFragment);
getSupportFragmentManager().putFragment(outState, SecondFragment.class.getName(), secondFragment);
}
and load them into onCreate method with:
if (savedInstanceState != null) {
firstFragment = (FirstFragment) getSupportFragmentManager().getFragment(savedInstanceState, FirstFragment.class.getName());
secondFragment = (SecondFragment) getSupportFragmentManager().getFragment(savedInstanceState, SecondFragment.class.getName());
}
My questions:
1. Is it the correct way to serialized fragment into activity screen orientation changes?
2. Sometimes I've the error: "Unmarshalling unknown type code 55 at offset 448", is it possible that it has caused by fragment serialization?"
EDIT:
I need to have the fragments as activity attributes because I've a listener interface into activity that:
#Override
public void executeTask(String what) {
secondFragment.executeTask(what);
}
this method was invoked into firstFragment. So the FirstFragment can execute a method of SecondFragment.
I'm not sure what may be the cause of the problem but I'll give you a hint that may help.
I don't think that you should reference the Fragments in the Adapter from the Activity.
Mainly due to the fact that it's pretty hard to synchronize the Activity life-cycle, Fragment lifecycle and ViewPager children life-cycles. And if any bugs emerge the debugging can be really painful.
Believe me, been there, done that...
By the way - is there a reason why you need references to Fragments in your Activity ?
EDIT
I don't think you should pass the information between the Fragments this way. In general the FragmentManager handles (creates, deletes) Fragments on it's own and you cannot be sure that these Fragments will be available at any time.
I think that the best way would be to move your data to separate model (database entry, SharedPreference or a singelton class) and then letting know the Adapter that data has changed (by a DataObserver in Fragments or simply notify the Adapter to update children data by calling notifyDataChanged).
EXAMPLE
FragmentA --->listener (reloadData())--->Activity--->adapter.notifyDataChanged()-----> fragmentB gets updated
This way if you ever want to add a ThirdFragment or in fact any number of Fragments that will use the Data you will not have to worry about updating data in any of these - just let the Adapter worry about it.
If your using same layout for portrait and landscape then When orientation change you can avoid activity recreate. change your manifest as...
<activity android:name=".activity.MainActivity"
android:configChanges="keyboardHidden|orientation|screenSize">
</activity>
and then override onConfigurationChanged() in activity ...
#Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
}

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