Reputation: 665
I have a Problem with a Android App compiled and running with target SDK 4.3. The App has two Activities, a MainActivity which is also the Launcher Activity and a SecondActivity. Both are using Fragments. To Support older Devices also, the support lib is used.
In the following scenario it comes to the "IllegalStateException: Fragment already added" Error.
1) Start the app -> MainActivity is shown
2) switch to the SecondActivity with an Intent
3) Press the Home Button
4) Wait a longer time (tested with 24 hours)
5) press again the app icon -> Exception. If the time is shorter, the SecondActivity is shown like expected.
I have read a lot of the IllegalStateExceptions during Fragment handling, but all all of them pointed to a problem with a replace() method. In the Stacktrace, my own code is never called.
The Fragement is added in the Activies onCreate() Method:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(..);
ListFragment listFragment = this.getCaptureListFragment();
FragmentTransaction tx = this.getSupportFragmentManager().beginTransaction();
tx.add(R.id.MainFragmentContainer, listFragment, "list_fragment_tag");
tx.commit();
}
private ListFragment getListFragment() {
ListFragment listFragment = (ListFragment) this.getSupportFragmentManager().findFragmentByTag("list_fragment_tag");
if (listFragment == null) {
listFragment = new ListFragment();
}
return listFragment;
}
java.lang.RuntimeException: Unable to start activity ComponentInfo{de.myexample.demo/de.myexample.demo.ui.SecondActivity}: java.lang.IllegalStateException: Fragment already added: ListFragment{42283f58 #0 id=0x7f060094 de.myexample.demo.ui.ListFragment}
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
at android.app.ActivityThread.access$600(ActivityThread.java:141)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5103)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalStateException: Fragment already added: ListFragment{42283f58 #0 id=0x7f060094 de.myexample.demo.ui.ListFragment}
at android.support.v4.app.FragmentManagerImpl.addFragment(SourceFile:1175)
at android.support.v4.app.BackStackRecord.run(SourceFile:616)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(SourceFile:1460)
at android.support.v4.app.FragmentActivity.onStart(SourceFile:556)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1171)
at android.app.Activity.performStart(Activity.java:5143)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2184)
... 11 more
java.lang.IllegalStateException: Fragment already added: ListFragment{42283f58 #0 id=0x7f060094 de.myexample.demo.ui.ListFragment}
at android.support.v4.app.FragmentManagerImpl.addFragment(SourceFile:1175)
at android.support.v4.app.BackStackRecord.run(SourceFile:616)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(SourceFile:1460)
at android.support.v4.app.FragmentActivity.onStart(SourceFile:556)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1171)
at android.app.Activity.performStart(Activity.java:5143)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2184)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
at android.app.ActivityThread.access$600(ActivityThread.java:141)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5103)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Upvotes: 13
Views: 30853
Reputation: 373
It is not necessary to create new boolean field for checking fragment's adding state. There is also a method in fragment.
Just use it:
myFragment.isAdded()
Upvotes: -3
Reputation: 7097
In order to reproduce this, one could activate "Don't keep activities" in Settings -> Developer options. Then pause and resume the activity.
That's so you don't have to wait 24 hours :)
Upvotes: 12
Reputation: 1675
The Fragment manager saves its state when exit. So you don't have to add your fragment again.
Do like this:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(..);
if (savedInstanceState == null) {
ListFragment listFragment = this.getCaptureListFragment();
FragmentTransaction tx = this.getSupportFragmentManager().beginTransaction();
tx.add(R.id.MainFragmentContainer, listFragment, "list_fragment_tag");
tx.commit();
}
}
Upvotes: 0
Reputation: 665
Okay, solved in on my own.
I put all Fragments out in onPause() and store the state in some booleans. Depending on that booleans the Fragments are put in in onResume(). Than the launch is stable regardless how long the Activity was in the background.
boolean addList = false;
@Override
protected void onResume() {
FragmentTransaction tx = this.getSupportFragmentManager().beginTransaction();
if (this.addList) {
ListFragment list = this.getListFragment();
tx.add(R.id.MainFragmentContainer, list, "list_fragment_tag");
}
tx.commit();
super.onResume();
this.addList = false;
}
@Override
protected void onPause() {
this.addList = this.getListFragment().isAdded();
...
if (this.addList) {
FragmentTransaction tx = this.getSupportFragmentManager().beginTransaction();
tx.remove(this.getListFragment());
tx.commit();
}
this.getSupportFragmentManager().executePendingTransactions();
super.onPause();
}
Maybe that helps someone with the same problem
Upvotes: 17