I am observing significant behavioral differences between the native LoaderManager and the version found in the support library. Specifically with regards to the retain behavior during configuration changes.
I originally began testing this behavior because I noticed the following bug with the support library LoaderManager, and I wanted to see if it worked better with the native APIs: Loader unable to retain itself during certain configuration change
I have written a simple test Activity to display the issue:
public class MainActivity extends Activity implements LoaderManager.LoaderCallbacks<String>, View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button button = new Button(this);
button.setText("Click Me");
button.setOnClickListener(this);
setContentView(button);
}
@Override
protected void onResume() {
super.onResume();
getLoaderManager().initLoader(1, null, this);
}
@Override
public Loader<String> onCreateLoader(int id, Bundle args) {
return new StringLoader(this);
}
@Override
public void onLoadFinished(Loader<String> loader, String data) {
Log.d("LoaderTest", "Loader Finished "+loader.toString());
}
@Override
public void onLoaderReset(Loader<String> loader) {
Log.d("LoaderTest", "Loader Reset "+loader.toString());
}
@Override
public void onClick(View v) {
startActivity(new Intent(this, SecondActivity.class));
}
private static class StringLoader extends Loader<String> {
public StringLoader(Context context) {
super(context);
}
@Override
protected void onStartLoading() {
deliverResult("Hi Mom!");
}
}
}
The SecondActivity in this example is just a dummy and can be anything. It was originally added to test the Launch -> Rotate -> Return case described in the linked SO issue (which still doesn't work in the support library today).
Running this application with the android.support.v4.FragmentActivity and Loader components from android.support.v4 as well, the behavior works as expected (minus the bug described in the link above). One can rotate the device multiple times, and on each rotation:
- The same
LoaderManagerinstance is returned from getLoaderManager() - The same
Loaderinstance is passed toonLoadFinished() onLoadFinished()is called immediately after each call toinitLoader()
Now, use the example above with all "native" components for Activity, LoaderManager, AsyncTaskLoader, etc. and the behavior changes dramatically. Rotate the device again a few times and:
- Now
onLoadFinished()will only be called every other rotation - When
onLoadFinished()is called, theLoaderinstance passed in is always new LoaderManageris also a different instance during these times- On the even rotations, the
LoaderManagerinstance doesn't change and it does return the sameLoaderfrominitLoader(); however, it'sonLoadFinished()never fires because theLoaderManagerclaims to not have been started (i.e. it's internalmStartedis false)
I truly hope I'm missing something quite obvious, because otherwise the behavior difference between the native LoaderManager versus the support library version proves to be a big problem. Especially as developers move off the support library and back into the native APIs.
Can anyone verify this behavior or expose what I'm doing wrong?