Android Loader not triggering callbacks on screen rotate
Asked Answered
A

2

14

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 :)

Ahmed answered 20/9, 2012 at 7:9 Comment(3)
I've also been struggling with this but am also new to Android. The only way I could make a difference was to make sure get(Support)LoaderManager() is called in the Activity's onCreate(), then it works even if initLoader() is called elsewhere. It's been tough debugging the sequence and lifetime of the internal loader variables in the Activity class, hopefully someone understands what is going on.Levitan
I likewise had this problem - I was calling getSupportLOaderManager().restart within a navigation listener.. instantiating it directly within onCreate and accessing it in the listener made it work but I have no idea why.. anyone?Stearoptene
onResume is usually the wrong place to do this stuff. More details in my answer.Tuberculous
T
25

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().

Tuberculous answered 24/1, 2014 at 9:8 Comment(1)
solved my strange problem that happen only for single fragment others are working fineZachery
B
1

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.

Belanger answered 13/4, 2013 at 14:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.