RulTech - Android: Fragments within Fragments

MAR

29

1793

Android: Fragments within Fragments

I was building out the settings stuff first (the app needs credentials to work so I kinda had to start there), which was relatively easy. I wanted to create a setup flow, whereby when you start the app it checks if you have credentials that are valid and if not walks through the setup procedure. I was using fragments to do this, each setup page being a different fragment rendered within the whole window in the main activity.

IUpon realising that I had already built a PreferenceFragment for the config settings a user had to setup at the beginning (they were easy to logically group this way) I thought I would just include that in one of the setup flow fragments and my config options would be all set up themselves. This worked rather nicely, until I got a rather nasty exception when I ran through the flow for a second time:

10-07 13:28:02.663: E/AndroidRuntime(1809): FATAL EXCEPTION: main
10-07 13:28:02.663: E/AndroidRuntime(1809): java.lang.RuntimeException: Unable to destroy activity {com.example.app/com.example.app.Base}: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
10-07 13:28:02.663: E/AndroidRuntime(1809): at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:3273)
10-07 13:28:02.663: E/AndroidRuntime(1809): at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:3291)
10-07 13:28:02.663: E/AndroidRuntime(1809): at android.app.ActivityThread.access$1200(ActivityThread.java:130)
10-07 13:28:02.663: E/AndroidRuntime(1809): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1248)
10-07 13:28:02.663: E/AndroidRuntime(1809): at android.os.Handler.dispatchMessage(Handler.java:99)
10-07 13:28:02.663: E/AndroidRuntime(1809): at android.os.Looper.loop(Looper.java:137)
10-07 13:28:02.663: E/AndroidRuntime(1809): at android.app.ActivityThread.main(ActivityThread.java:4745)
10-07 13:28:02.663: E/AndroidRuntime(1809): at java.lang.reflect.Method.invokeNative(Native Method)
10-07 13:28:02.663: E/AndroidRuntime(1809): at java.lang.reflect.Method.invoke(Method.java:511)
10-07 13:28:02.663: E/AndroidRuntime(1809): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
10-07 13:28:02.663: E/AndroidRuntime(1809): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
10-07 13:28:02.663: E/AndroidRuntime(1809): at dalvik.system.NativeStart.main(Native Method)
10-07 13:28:02.663: E/AndroidRuntime(1809): Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
10-07 13:28:02.663: E/AndroidRuntime(1809): at android.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1280)
10-07 13:28:02.663: E/AndroidRuntime(1809): at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1291)
10-07 13:28:02.663: E/AndroidRuntime(1809): at android.app.BackStackRecord.commitInternal(BackStackRecord.java:548)
10-07 13:28:02.663: E/AndroidRuntime(1809): at android.app.BackStackRecord.commit(BackStackRecord.java:532)
10-07 13:28:02.663: E/AndroidRuntime(1809): at com.kodhus.tropics.setup.SetupCredsFragment.onDestroy(SetupCredsFragment.java:24)
10-07 13:28:02.663: E/AndroidRuntime(1809): at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:983)
10-07 13:28:02.663: E/AndroidRuntime(1809): at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1035)
10-07 13:28:02.663: E/AndroidRuntime(1809): at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1017)
10-07 13:28:02.663: E/AndroidRuntime(1809): at android.app.FragmentManagerImpl.dispatchDestroy(FragmentManager.java:1826)
10-07 13:28:02.663: E/AndroidRuntime(1809): at android.app.Activity.performDestroy(Activity.java:5171)
10-07 13:28:02.663: E/AndroidRuntime(1809): at android.app.Instrumentation.callActivityOnDestroy(Instrumentation.java:1109)
10-07 13:28:02.663: E/AndroidRuntime(1809): at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:3260)
10-07 13:28:02.663: E/AndroidRuntime(1809): ... 11 more

I had a Google and was surprised to find endless Stack Overflow posts saying “Fragments in fragments can’t be done”. Well I may be new to this version of Android development but that seemed a little foolish and also acted like a red flag to a bull. So I had a hunt around and it turns out it is possible to do fragments within fragments, but you just have to clean up after yourself – activities only clean up the top level fragments in them when they are closed or transitioned etc.

Thus I had a half hour of playing around trying to find the right settings, and this is the code I came up with. It goes in the onDestroy method of the middle fragment, i.e. the one that is within the activity and has another fragment within it. Note that you need to know the ID of the inner fragment for this to work.

 
@Override
public void onDestroy() 
{
        Fragment fragment = getFragmentManager().findFragmentById(R.id.innerfragment);
            if (fragment.isResumed()) 
               {
                  getFragmentManager().beginTransaction().remove(fragment).commit();
               }
        super.onDestroy();
}

Add Comment

COMPANY INTRO

RulTech is a provider of total IT support & services viz. Installation, Configuration, Maintenance, Troubleshooting, Mobile development (iPhone & Android applications), Web Development (Java, dot net, PHP, Word Press, Joomla open source), Content writing & Data Analysis.

BLOG POSTS