serenskye
serenskye

Reputation: 3467

Android Loader not triggering callbacks on screen rotate

I am using an AsyncTaskLoader. I have an activity which has implemented LoaderCallbacks (Support library).

I have breakpoint debugged and put in logs, the loader delivers the result, however the second time the callback onLoadFinished is not triggered. The odd thing - when I rotate back again it works, which ever orientation I start on gets callbacks when I return to it.

In my Activity onResume:

LoaderManager lm = getSupportLoaderManager();
Loader loader = lm.initLoader(0, null, new LoaderManager.LoaderCallbacks<String>() {

        @Override
        public Loader<String> onCreateLoader(int i, Bundle bundle) {
            Loader<String> loader = new TestLoader(MainActivity.this);
            return loader;
        }

        @Override
        public void onLoadFinished(Loader<String> stringLoader, String s) {
            Log.d(Application.TAG, "OnLoadFinished " + s);
            doStuff(s);
        }

        @Override
        public void onLoaderReset(Loader<String> stringLoader) {
            // NOP
        }
    });

In my loader:

public class TestLoader extends AsyncTaskLoader<String> {
    private String mData;

    public TestLoader(Context context) {
        super(context);
    }

    // This get's called after a loader is initialized or a loader 
    // that is alive still is reset
    @Override
    public void onStartLoading() {
        if (mData != null) { // Have our data loaded, just deliver it!
            deliverResult(mData);
        }
        if (takeContentChanged() || mData == null) {
            forceLoad();
        }
    }

    // This is called when an Activity or Fragment requests a loader 
    // to be reset because they want new data
    @Override
    public void onReset() {
        mData = null;
        // Ensure that the old task is cancelled if it was running
        // We do NOT have to call forceLoad here because onStartLoading 
        // will get called after this
        cancelLoad();
    }

    // Here we just want to store our own data we got and reset our boolean
    @Override
    public void deliverResult(String data) {
        Log.d(Application.TAG, "deliverResult " + data);
        mData = data;
        super.deliverResult(mData);
    }

    @Override
    public String loadInBackground() {
       // returns content from a content provider ... 
    }
}

Really baffled by this one, I am new to Android so maybe this is obvious to someone else :)

Upvotes: 14

Views: 4503

Answers (2)

Dave Truby
Dave Truby

Reputation: 193

You have

Loader loader = lm.initLoader(...)

You should have

Loader loader = new LoaderManager.LoaderCallbacks(...) {...}

and in your onResume()

this.getLoaderManager().restartLoader(0, null, this.loader);

See Loaders documentation.

Upvotes: 1

Monstieur
Monstieur

Reputation: 8102

You must at least simply call getSupportLoaderManager() / getLoaderManager() in onCreate() if it's an Activity or onActivityCreated() if it's a Fragment. The actual initLoader() can be elsewhere. Otherwise the loader will be in a stopped state and won't deliver the results even though it completes the load. I suspect it's because the loader manager doesn't reattach the old loaders to the new Activity unless the above call is made in the new Activity's onCreate().

Upvotes: 25

Related Questions