Search code examples
androidandroid-fragmentsandroid-bundlestartactivityforresultandroid-savedstate

Fragment's bundle is null in onCreate despite overriding onSaveInstanceState


My MainActivity uses Fragments, a simplified version of the layout looks like this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    tools:context=".MainActivity">

    <fragment
        android:name="com.lafave.MyFragment1"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"/>

    <View
        android:layout_width="@dimen/divider_width"
        android:layout_height="match_parent"
        android:background="@android:color/darker_gray" />

    <fragment
        android:name="com.lafave.MyFragment2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

From within a Fragment, I use the following code to launch the native camera application:

mRecentPhotoPath = file.getAbsolutePath();
final Uri uri = Uri.fromFile(file);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);

My Fragment's onActivityResult method depends on the value of mRecentPhotoPath being preserved:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
            //mRecentPhotoPath is used here to display the photo.
    }
}

However, if I rotated the device while the native camera app was running then a new instance of my Fragment will be created and mRecentPhotoPath will not be preserved. I thought I could solve this problem by implementing onSaveInstanceState in the Fragment as so:

@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
    super.onSaveInstanceState(outState);
    if(mRecentPhotoPath != null) {
        outState.putString(RECENT_PHOTO_PATH_ARUGMENT, mRecentPhotoPath);
    }
}

However, even though I'm saving state to the bundle, when the Fragment is restored the onCreateView, onActivityCreated, and onViewStateRestored methods always have null for their bundle. What am I doing wrong?

In fact, this seems to be an issue regardless of the camera. If I rotate my app (without having opened the native camera), then the Bundles are always null in the various methods like onCreateView.


Solution

  • Thanks @EpicPandaForce, you put me on the right path. The problem was because my MainActivity's layout didn't use an id on the Fragment. Making this change fixed my issues:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/activity_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        tools:context=".MainActivity">
    
        <fragment
            android:id="@+id/myFragment1"
            android:name="com.lafave.MyFragment1"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"/>
    
        <View
            android:layout_width="@dimen/divider_width"
            android:layout_height="match_parent"
            android:background="@android:color/darker_gray" />
    
        <fragment
            android:id="@+id/myFragment2"
            android:name="com.lafave.MyFragment2"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    
    </LinearLayout>