1

I have an activity with 2 fragments, and one inner-fragment or nested-fragment.

The flow of how activity and fragments are created:

Activity -> fragment 1 -> fragment 2 + nested-fragment

  • fragment 1 is added to the layout when activity is created
  • fragment 2 is created when a button is pressed from fragment 1.
  • fragment 1 is replaced with fragment 2.
  • When fragment 2 is created, automatically the nested-fragment (SupportMapFragment) is added to fragment 2.

I am trying to simulate: android killing paused-activity (android system can kill activities which are paused if the system requires -e.g when no more memory remains-).

How I do this? I'm pressing the home button, then from DDMS (eclipse) I press the STOP method. After this I am re-launching the app from the android-device menu.

  • Note 1: I am on fragment 2 + Support Map Fragment
  • Note 2: SupportMapFragment is attached to the parent fragment (fragment 2) with getChildFragmentManager().

If I do this (pressing the home button then I destroy the app from DDMS), I am keep getting this exception:

08-15 06:11:14.127: E/AndroidRuntime(3205): FATAL EXCEPTION: main
08-15 06:11:14.127: E/AndroidRuntime(3205): Process: com.zbarcea.forks, PID: 3205
08-15 06:11:14.127: E/AndroidRuntime(3205): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.zbarcea.forks/com.zbarcea.forks.activities.ActivityMain}: android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment com.zbarcea.forks.fragments.FragmentMapMode$4: make sure class name exists, is public, and has an empty constructor that is public
08-15 06:11:14.127: E/AndroidRuntime(3205):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2195)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at android.app.ActivityThread.access$800(ActivityThread.java:135)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at android.os.Handler.dispatchMessage(Handler.java:102)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at android.os.Looper.loop(Looper.java:136)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at android.app.ActivityThread.main(ActivityThread.java:5017)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at java.lang.reflect.Method.invokeNative(Native Method)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at java.lang.reflect.Method.invoke(Method.java:515)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at dalvik.system.NativeStart.main(Native Method)
08-15 06:11:14.127: E/AndroidRuntime(3205): Caused by: android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment com.zbarcea.forks.fragments.FragmentMapMode$4: make sure class name exists, is public, and has an empty constructor that is public
08-15 06:11:14.127: E/AndroidRuntime(3205):     at android.support.v4.app.Fragment.instantiate(Fragment.java:413)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at android.support.v4.app.FragmentState.instantiate(Fragment.java:97)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at android.support.v4.app.FragmentManagerImpl.restoreAllState(FragmentManager.java:1790)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at android.support.v4.app.Fragment.performCreate(Fragment.java:1489)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:893)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1086)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at android.support.v4.app.FragmentManagerImpl.dispatchCreate(FragmentManager.java:1879)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:215)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at com.zbarcea.forks.activities.BaseSlidingMenuFragmentActivity.onCreate(BaseSlidingMenuFragmentActivity.java:93)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at com.zbarcea.forks.activities.ActivityMain.onCreate(ActivityMain.java:205)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at android.app.Activity.performCreate(Activity.java:5231)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2159)
08-15 06:11:14.127: E/AndroidRuntime(3205):     ... 11 more
08-15 06:11:14.127: E/AndroidRuntime(3205): Caused by: java.lang.InstantiationException: can't instantiate class com.zbarcea.forks.fragments.FragmentMapMode$4; no empty constructor
08-15 06:11:14.127: E/AndroidRuntime(3205):     at java.lang.Class.newInstanceImpl(Native Method)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at java.lang.Class.newInstance(Class.java:1208)
08-15 06:11:14.127: E/AndroidRuntime(3205):     at android.support.v4.app.Fragment.instantiate(Fragment.java:402)
08-15 06:11:14.127: E/AndroidRuntime(3205):     ... 24 more

So, I have tried to remove the SupportMapFragment every time when the parent fragment (fragment 2) is calling onPause().

    @Override
    public void onPause()
    {
        super.onPause();

        infoWindowAdapterMapMode = null;

        getChildFragmentManager().beginTransaction().remove(supportMapFragment).commit();

        supportMapFragment = null;
    }

Problem solved! If I destroy the activity and I am resuming the app, the fragment is re-created and no exception !

The problem occurres when I'm pressing the home button (not calling STOP from DDMS) too fast, before the support map fragment is created.

I am getting this exception:

08-15 06:24:50.679: E/AndroidRuntime(3275): FATAL EXCEPTION: main
08-15 06:24:50.679: E/AndroidRuntime(3275): Process: com.zbarcea.forks, PID: 3275
08-15 06:24:50.679: E/AndroidRuntime(3275): java.lang.NullPointerException
08-15 06:24:50.679: E/AndroidRuntime(3275):     at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:651)
08-15 06:24:50.679: E/AndroidRuntime(3275):     at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1467)
08-15 06:24:50.679: E/AndroidRuntime(3275):     at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:440)
08-15 06:24:50.679: E/AndroidRuntime(3275):     at android.os.Handler.handleCallback(Handler.java:733)
08-15 06:24:50.679: E/AndroidRuntime(3275):     at android.os.Handler.dispatchMessage(Handler.java:95)
08-15 06:24:50.679: E/AndroidRuntime(3275):     at android.os.Looper.loop(Looper.java:136)
08-15 06:24:50.679: E/AndroidRuntime(3275):     at android.app.ActivityThread.main(ActivityThread.java:5017)
08-15 06:24:50.679: E/AndroidRuntime(3275):     at java.lang.reflect.Method.invokeNative(Native Method)
08-15 06:24:50.679: E/AndroidRuntime(3275):     at java.lang.reflect.Method.invoke(Method.java:515)
08-15 06:24:50.679: E/AndroidRuntime(3275):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
08-15 06:24:50.679: E/AndroidRuntime(3275):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
08-15 06:24:50.679: E/AndroidRuntime(3275):     at dalvik.system.NativeStart.main(Native Method)

And that's it. I cannot identify the source of the exception, because it crashes somewhere in the support library.

Zbarcea Christian
  • 9,367
  • 22
  • 84
  • 137

1 Answers1

0

First: I like your approach of being concentrated on a clean and proper state handling of your application.Excellent! But, as you said: Android can kill activities and manage their lifecycle for itself. The OS may release memory allocated for your activity as soon as possible requiring you to allocate it again. This means your fragment may or may not get destroyed. As you can see in your stack trace, FragmentActivity.onCreate is called. This obviously inddicates your existing resources created within the context of the old activity are not access - able anymore. The only context that is guaranted to exist through your application lifecycle is the application context. For all other resources you should be aware and handle properly that created resources may be invalid at the time you are trying to access them.

Peter
  • 1,769
  • 1
  • 14
  • 18