Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IllegalStateException: Can't change container ID of Fragment

Android platform: 3.1

I am trying to move a fragment from a container A to a container B. Here follows the code to accomplish this:

private void reattach(int newContainerId, Fragment frag, String tag) {        if (frag == null || !frag.isAdded() || (frag.getId() == newContainerId)) { return; }        final FragmentManager fm = getFragmentManager();       FragmentTransaction ft = fm.beginTransaction();       ft.remove(frag);     //stacco il frammento dal container A       ft.commit();       fm.executePendingTransactions();        ft = fm.beginTransaction();       ft.add(newContainerId, frag, tag); //attacco il frammento sul container D       ft.commit();       fm.executePendingTransactions();       } 

When I run the system, I get the following IllegalStateException:

03-26 00:13:14.829: E/AndroidRuntime(30090): java.lang.RuntimeException: Unable to start activity ComponentInfo{eu.areamobile.apps.sfa/eu.areamobile.apps.sfa.activity.HomeActivity}: java.lang.IllegalStateException: Can't change container ID of fragment FragmentHomeController{408202a8 id=0x7f050010 HomeController}: was 2131034128 now 2131034132 03-26 00:13:14.829: E/AndroidRuntime(30090):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1751) 03-26 00:13:14.829: E/AndroidRuntime(30090):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1767) 03-26 00:13:14.829: E/AndroidRuntime(30090):    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3117) 03-26 00:13:14.829: E/AndroidRuntime(30090):    at android.app.ActivityThread.access$1600(ActivityThread.java:122) 03-26 00:13:14.829: E/AndroidRuntime(30090):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1009) 03-26 00:13:14.829: E/AndroidRuntime(30090):    at android.os.Handler.dispatchMessage(Handler.java:99) 03-26 00:13:14.829: E/AndroidRuntime(30090):    at android.os.Looper.loop(Looper.java:132) 03-26 00:13:14.829: E/AndroidRuntime(30090):    at android.app.ActivityThread.main(ActivityThread.java:4028) 03-26 00:13:14.829: E/AndroidRuntime(30090):    at java.lang.reflect.Method.invokeNative(Native Method) 03-26 00:13:14.829: E/AndroidRuntime(30090):    at java.lang.reflect.Method.invoke(Method.java:491) 03-26 00:13:14.829: E/AndroidRuntime(30090):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:844) 03-26 00:13:14.829: E/AndroidRuntime(30090):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602) 03-26 00:13:14.829: E/AndroidRuntime(30090):    at dalvik.system.NativeStart.main(Native Method) 03-26 00:13:14.829: E/AndroidRuntime(30090): Caused by: java.lang.IllegalStateException: Can't change container ID of fragment FragmentHomeController{408202a8 id=0x7f050010 HomeController}: was 2131034128 now 2131034132 03-26 00:13:14.829: E/AndroidRuntime(30090):    at android.app.BackStackRecord.doAddOp(BackStackRecord.java:338) 03-26 00:13:14.829: E/AndroidRuntime(30090):    at android.app.BackStackRecord.add(BackStackRecord.java:316) 03-26 00:13:14.829: E/AndroidRuntime(30090):    at eu.areamobile.apps.sfa.activity.HomeActivity.reattach(HomeActivity.java:340) 03-26 00:13:14.829: E/AndroidRuntime(30090):    at eu.areamobile.apps.sfa.activity.HomeActivity.customHideShowCreate(HomeActivity.java:253) 03-26 00:13:14.829: E/AndroidRuntime(30090):    at eu.areamobile.apps.sfa.activity.HomeActivity.customHideShowCreate(HomeActivity.java:155) 03-26 00:13:14.829: E/AndroidRuntime(30090):    at eu.areamobile.apps.sfa.activity.HomeActivity.onPostCreate(HomeActivity.java:66) 03-26 00:13:14.829: E/AndroidRuntime(30090):    at android.app.Instrumentation.callActivityOnPostCreate(Instrumentation.java:1111) 03-26 00:13:14.829: E/AndroidRuntime(30090):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1734) 

After a quick debug, I noticed that on Android 3.1 the FragmentTransaction.remove doesn't set to 0 the mContainerId of the fragment being removed, while on ICS it works correctly.
Any suggestions or workarounds?

like image 970
Matthew Avatar asked Mar 28 '12 11:03

Matthew


1 Answers

My solution to this problem is to re-create the fragment while keeping its state:

FragmentTransaction ft = mFragmentManager.beginTransaction(); ft.remove(old); Fragment newInstance = recreateFragment(old); ft.add(R.id.new_container, newInstance); ft.commit(); 

With the following helper function:

private Fragment recreateFragment(Fragment f)     {         try {             Fragment.SavedState savedState = mFragmentManager.saveFragmentInstanceState(f);              Fragment newInstance = f.getClass().newInstance();             newInstance.setInitialSavedState(savedState);              return newInstance;         }         catch (Exception e) // InstantiationException, IllegalAccessException         {             throw new RuntimeException("Cannot reinstantiate fragment " + f.getClass().getName(), e);         }     } 

It works for me, at least with the latest support library (r11), although I didn't test much yet.

The extra cost is to instantiate the fragment twice.

like image 67
sstn Avatar answered Oct 03 '22 13:10

sstn