LoaderCallbacks.onLoadFinished is not called when the loader is reused and contains data
I have 1 activity and 2 fragments. Both fragments use a custom AsyncTaskLoader to get some data from the web service, and since I’m using a loader, it should recreate the persisted data across activities and fragments. Both fragments override the onActivityCreated method and call getLoaderManager().initLoader(0, null, this) to create a new loader or reuse an existing loader.
When an activity is first created, Fragment #1 is added to the FrameLayout by default, the data is loaded, and the LoaderCallbacks.onLoadFinished() method is called internally and the result is displayed. I have a button that replaces Fragment #1 with Fragment #2 when clicked, and Fragment #1 is pushed to the fragment-backstack. When the user presses the BACK key, it switches back to Fragment #1.
onActivityCreated is called again on Fragment #1, and then apparently iniLoader() again. This time the data is already present in the loader, and I want it to automatically call the LoaderCallbacks.onLoadFinished method again because it already has data available, as follows: http://goo.gl/EGFJk
Ensures a loader is initialized and active. If the loader doesn’t already exist, one is created and (if the activity/fragment is currently started) starts the loader. Otherwise the last created loader is re-used.
In either case, the given callback is associated with the loader, and will be called as the loader state changes. If at the point of call the caller is in its started state, and the requested loader already exists and has generated its data, then callback onLoadFinished(Loader, D) will be called immediately (inside of this function), so you must be prepared for this to happen.
But even if the loader exists and has generated data ready for delivery, the method is never called.
Edit #1
Questions from the user’s perspective:
- The user starts the activity and sees fragment1 with some data
- The user clicks somewhere to change the first fragment to another fragment, with a different one
Data - The user presses the back key
- The user now looks at fragment1 again, but there is no data. (This means I need to get it from the web service again – I want to avoid this if possible)
This is my Activity :
public class FragmentTestsActivity extends Activity implements OnClickListener {
private Button btn1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btn1 = (Button) findViewById(R.id.btn1);
btn1.setOnClickListener(this);
Fragment newFragment = new Fragment1();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(R.id.fragmentContainer, newFragment).commit();
}
@Override
public void onClick(View view) {
int id = view.getId();
if (id == R.id.btn1) {
showNewFragment();
}
}
public void showNewFragment() {
Instantiate a new fragment.
Fragment2 newFragment = new Fragment2();
Add the fragment to the activity, pushing this transaction
on to the back stack.
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.fragmentContainer, newFragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
}
}
My fragment #1:
public class Fragment1 extends Fragment implements LoaderCallbacks<String> {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment1, container, false);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
LoaderManager.enableDebugLogging(true);
getLoaderManager().initLoader(0, null, this);
}
private static class TestLoader extends AsyncTaskLoader<String> {
String result;
public TestLoader(Context context) {
super(context);
}
@Override
public String loadInBackground() {
Some long-running call to a webservice - replaced with a simple string to test with
return "FirstTimeData";
}
@Override
public void deliverResult(String data) {
result = data;
if (isStarted()) {
super.deliverResult(data);
}
}
@Override
protected void onStartLoading() {
if (result != null) {
deliverResult(result);
}
if (takeContentChanged() || result == null) {
forceLoad();
}
}
@Override
protected void onStopLoading() {
cancelLoad();
}
}
@Override
public Loader<String> onCreateLoader(int id, Bundle args) {
return new TestLoader(getActivity());
}
@Override
public void onLoadFinished(Loader<String> loader, String result) {
Log.d("Fragment1", "onLoadFinished: " + result);
}
@Override
public void onLoaderReset(Loader<String> loader) {
TODO Auto-generated method stub
}
}
Anyone know the solution to this problem or am I doing something wrong here? Any help is greatly appreciated.
Solution
The correct answer, at least for me, is to move the entire Loader initialization from onViewCreated or onActivityCreated to onStart.
Everything worked fine after that!