1

I am using the support library and am using an AsyncTaskLoader. Why doesn't the constructor of the AsycTaskLoader not accepting a Fragment as a parameter?

I only want the AsyncTaskLoader to start loading data when it is called or initialized inside my fragments. But as of now, at anytime the Activity goes to onResume it restarts all the loaders I initialized on different fragments. I believe this is mainly because I am passing fragment.getActivity() in the constructor of my AsyncTaskLoader instances.

Any way to do this?

So far, I am wrapping the initialization of the loaders in a fragment and each have an inner AsyncTaskLoader, which I customized as well. Then when the fragment is initialized, in the onCreateView method, I then call the method like so :

initLoader();

initLoader() method

public Loader<Object> initLoader() {
    return getLoaderManager().initLoader(LOADER_ID.DUMMIES, null, new LoaderCallbacks<Object>() {
        @Override
        public Loader<Object> onCreateLoader(int id, Bundle args) {
            Loader<Object> loader = new CustomLoader<Object>(getActivity()) {
                @Override
                public Object loadInBackground() {
                    return DummyGenerator.generateDummyEntriesToDb();;
                }
            };
            return loader;
        }

        @Override
        public void onLoadFinished(Loader<Object> loader, Object data) {
            setToDb(data);
        }

        @Override
        public void onLoaderReset(Loader<Object> loader) {

        }
    });
}

CustomLoader.java - generic implementation I suited to my needs. The releaseResources method is not filled in but I left it there for future usage.

public class CustomLoader<T> extends AsyncTaskLoader<T> {

    T mData;

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

    @Override
    public T loadInBackground() {
        return null;
    }

    @Override
    public void deliverResult(T data) {
        if (isReset()) {
            releaseResources(data);
            return;
        }

        T oldData = mData;
        mData = data;

        if (isStarted()) {
            super.deliverResult(data);
        }

        if (oldData != null && oldData != data) {
            releaseResources(oldData);
        }
    }

    @Override
    protected void onStartLoading() {
        if (mData != null) {
            deliverResult(mData);
        }

        if (takeContentChanged() || mData == null) {
            forceLoad();
        }
    }

    @Override
    protected void onStopLoading() {
        cancelLoad();
    }

    @Override
    protected void onReset() {
        onStopLoading();

        if (mData != null) {
            releaseResources(mData);
            mData = null;
        }

    }

    @Override
    public void onCanceled(T data) {
        super.onCanceled(data);
        releaseResources(data);
    }

    public void releaseResources(T data) {

    }
}

The generateDummyEntriesToDb method is working fine just creating list of the objects I am using, as well as the setToDb() method. The problem is when the activity goes to onResume the loadnBackground() method is called again thus I am compelled to think that all the other loaders behave the same way.

John Ernest Guadalupe
  • 6,379
  • 11
  • 38
  • 71

1 Answers1

1

The Context provided should be the Activity attached to the Fragment. Be sure you are initializing the loader via the LoaderManager as it is tied to the appropriate object life cycle. So when initializing from within a Fragment, you should use Fragment.getLoaderManager(). Then call LoaderManager.initLoader() appropriately.

Larry Schiefer
  • 15,687
  • 2
  • 27
  • 33
  • Please see updated answer. The problem is, even when the fragment I have used to initialized the immediate LoaderManager and the Loader I used is destroyed and a new fragment is already shown on the screen, when the Actiivity goes to onResume, i.e. pressing home button then going back to the app, the other loaders are re-run, even when the fragment used to initialize them are already gone – John Ernest Guadalupe Oct 12 '15 at 04:07
  • 1
    This is most likely happening because your `initLoader()` is being called from `onCreateView()` and your `Fragments` are being destroyed for some reason. Almost sounds like they are inside of a `ViewPager` so they are being created but not shown. I'd also recommend not using an anonymous inner instance of a `LoaderCallback` implementation - it's confusing to read and can lead to strange references and memory build up. – Larry Schiefer Oct 12 '15 at 13:27
  • No they are not inside a ViewPager actually. They are created and replaced on a ViewGroup when an item is clicked from a Navigation Drawer, so they should only be initialized once when the fragment is created and then destroyed when the fragment is not visible anymore right? But what happens is whenever the activity goes to onResume all the past loaders are started again – John Ernest Guadalupe Oct 13 '15 at 07:38
  • 1
    It's tough to say exactly what is happening without seeing all of the code. However, the loaders shouldn't be getting re-created each time `onResume()` is called. They may get triggered again, but they shouldn't be completely re-created. – Larry Schiefer Oct 13 '15 at 10:36
  • It really is just a simple fragment switching logic on a viewgroup. And I call the initLoader method in the onCreateView of the fragment. Any advise how I can stop them from trigerring in onResume? – John Ernest Guadalupe Oct 14 '15 at 03:22
  • 1
    What else is happening in `onResume()`? Is anything else going on with the `ViewGroup`? It's definitely not normal that all of the `Fragment` instances are re-creating their view hierarchy (via `onCreateView()`) just because your `Activity` has resumed. I would look there and understand why that is happening. – Larry Schiefer Oct 14 '15 at 11:19