javaandroidandroid-dialogfragmentandroid-inflate

Android DialogFragment and Unable to start activity ComponentInfo after killing/restoring app


I have app working fine until one very specific scenario.

  1. I open the dialog.
  2. I kill the app (using SystemTuner)
  3. I restore app after being killed.

Then my app is not run and the following messages are in LogCat.

    07-05 20:45:36.469: W/ResourceType(4866): No package identifier when getting value for resource number 0x00000000
07-05 20:45:36.469: W/dalvikvm(4866): threadid=1: thread exiting with uncaught exception (group=0x40a7b390)
07-05 20:45:36.469: E/AndroidRuntime(4866): FATAL EXCEPTION: main
07-05 20:45:36.469: E/AndroidRuntime(4866): java.lang.RuntimeException: Unable to start activity ComponentInfo{petersoft.petermemoflashcards/petermemo.android.gui.activities.MainActivity}: android.content.res.Resources$NotFoundException: Resource ID #0x0
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1964)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1989)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.app.ActivityThread.access$600(ActivityThread.java:126)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1155)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.os.Handler.dispatchMessage(Handler.java:99)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.os.Looper.loop(Looper.java:137)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.app.ActivityThread.main(ActivityThread.java:4482)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at java.lang.reflect.Method.invokeNative(Native Method)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at java.lang.reflect.Method.invoke(Method.java:511)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:787)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:554)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at dalvik.system.NativeStart.main(Native Method)
07-05 20:45:36.469: E/AndroidRuntime(4866): Caused by: android.content.res.Resources$NotFoundException: Resource ID #0x0
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.content.res.Resources.getValue(Resources.java:1041)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.content.res.Resources.loadXmlResourceParser(Resources.java:2191)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.content.res.Resources.getLayout(Resources.java:880)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.view.LayoutInflater.inflate(LayoutInflater.java:394)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at petermemo.android.gui.dialogs.PMDialogFragment.onCreateView(PMDialogFragment.java:51)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at petermemo.android.gui.dialogs.DialogCardStats.onCreateView(DialogCardStats.java:61)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.support.v4.app.Fragment.performCreateView(Fragment.java:1478)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:927)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1086)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1877)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:552)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1133)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.app.Activity.performStart(Activity.java:4475)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1937)
07-05 20:45:36.469: E/AndroidRuntime(4866):     ... 11 more

There is part of dialog code:

public abstract class PMDialogFragment extends DialogFragment {

    @Override
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);

        setRetainInstance(true);  
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View view = inflater.inflate(layoutId, container);

        return view;
    }

@Override
    public void onDestroyView() {
        if (getDialog() != null && getRetainInstance())
            getDialog().setDismissMessage(null);
        super.onDestroyView();
    }

}

The following line causes the exception:

View view = inflater.inflate(layoutId, container);

Please also note that as I said, if app is not killed, it works fully ok. Even if it's hidden and restored, no problems.

I don't have the smallest idea what is the reason of problems... Please help. :)

Added later:

I'm wondering perhaps it can be related with fact that layoutId is equal to zero. I didn't paste previously the whole code but class PMDialogFragment is used by child class in the following way:

public class DialogCardStats extends PMDialogFragment {

public static DialogCardStats newInstance (Fragment fragment, String fragmentTag, InterfaceCallback.Callback callback, Bundle bundle) {
        FragmentManager fm = fragment.getFragmentManager();
        DialogCardStats dialogCardStats = new DialogCardStats();
        dialogCardStats.setArguments(bundle);
        dialogCardStats.layoutId = R.layout.dialog_card_stats;
        dialogCardStats.registerCallbackListener(callback);
        dialogCardStats.show(fm, fragmentTag); 
        return dialogCardStats;
    }

When my dialog is displayed using newInstance, then layoutId is set correctly. However when it's restored automatically by Android, layoutId is zero. How should I retain important class fields?


Solution

  • When the system re-creates an activity with fragments that have been destroyed, fragments that were present at the moment of destruction are automatically instantiated and re-added to the activity's fragment manager. However, instantiation in this case happens by means of reflection, i.e. automatic call to the no-arg constructor of your fragment classes. Therefore, this re-instantiation does not pass through your newInstance static method.

    The mistake in this case - one that I personally did commit in an old project, so I can sympathize - is that you are saving values through direct assignment to instance variables, e.g.

    dialogCardStats.layoutId = R.layout.dialog_card_stats;
    

    instead of using the arguments bundle. See, the arguments bundle is automatically saved and restored for you, while those instance variables are never restored after activity/fragment destruction and re-creation.

    The correct way of doing it is to leverage the arguments bundle, e.g.

    bundle.putInt(ARG_LAYOUT_ID, R.layout.dialog_card_stats);
    

    where ARG_LAYOUT_ID is a private static final variable (i.e. a constant) in the DialogCardStats class, then using the constant again in onCreateView to extract the resource identifier, e.g.

    int layoutId = getArguments().getInt(ARG_LAYOUT_ID);
    View view = inflater.inflate(layoutId, container);
    

    and everything should run fine.