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)
oronRestoreInstanceState(Bundle)
. But in the case of (1), as well as switching Activities, neitheronCreate(Bundle)
noronRestoreInstanceState(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)
setRetainInstance(false)
isnt working in my case. (1) WhensetRetainInstance(true)
, as docs says, it callsonDetach()
thenonAttach()
, and skiponDestroy()
&onCreate()
. (2) Thus it means whensetRetainInstance(false)
, the Fragment will beonDestroy()
thenonCreate(Bundle)
. This meanssetRetainInstance()
is not something dealing with "keeping/removing" the Fragment. It controls only "retain/recreate" it instead. – Arand