justanoob justanoob - 2 months ago 10
Android Question

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
?

Answer

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.