Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Instance variable becomes null in retained Fragment

As an alternative to an Intent, i'm saving data in a retained headless Fragment during Activity re-creation (my saved object can be pretty large and it wouldn't fit the size limit of an Intent, and i think this is a faster approach than serializing-deserializing into JSON for example).

I've got the idea from this Google documentation, although my implementation is a bit different.

The Fragment:

public class DataFragment extends Fragment {

    private Data data;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
    }

    public void setData(Data data) {
        this.data = data;
    }

    public Data getData() {
        return data;
    }
}

I save my data to this Fragment in the onSaveInstanceState() method of my Activity:

@Override
protected void onSaveInstanceState(Bundle outState) {
    FragmentManager fm = getSupportFragmentManager();
    dataFragment = (DataFragment) fm.findFragmentByTag(TAG_DATA);
    if (dataFragment == null) {
        dataFragment = new DataFragment();
        fm.beginTransaction().add(dataFragment, TAG_DATA).commitNow();
    }
    dataFragment.setData(myData);
    super.onSaveInstanceState(outState);
}

And the relevant part of onCreate():

Data data;
FragmentManager fm = getSupportFragmentManager();
dataFragment = (DataFragment) fm.findFragmentByTag(TAG_DATA);
if (dataFragment == null) {
    // the Fragment is not attached, fetching data from DB
    DatabaseManager dbm = DatabaseManager.getInstance(this);
    data = dbm.getData();
} else {
    // the Fragment is attached, fetching the data from it
    data = dataFragment.getData();
    fm.beginTransaction().remove(dataFragment).commitNow();
}

This works flawlessly on orientation changes.

The problem is, sometimes, when my app is in the background and i'm returning to it, dataFragment.getData() returns null.

In other words, in the following line in onCreate() sometimes data is null:

data = dataFragment.getData();

How is this possible?

It does not throw a NullPointerException, so dataFragment is not null for sure.

Why did its initialized instance variable became null?

like image 777
justanoob Avatar asked Sep 30 '16 07:09

justanoob


1 Answers

What you experience is PROCESS DEATH.

Technically it's also called "low memory condition".

The retained fragment is killed along with the application, but the FragmentActivity recreates your retained fragment in super.onCreate(), so you'll find it by its tag but the data in it won't be initialized.

Put the app in background then press the red X in the bottom left in Android Studio to kill the process. That recreates this phenomenon.

terminate button

NOTE: After AS 4.0, if you launch your app from AS, then "Terminate" will trigger Force Stop (which does not produce this phenomenon). But if you launch your app from LAUNCHER on the phone after that, then you'll get this phenomenon.

like image 167
EpicPandaForce Avatar answered Sep 28 '22 07:09

EpicPandaForce