AsyncTaskLoader doesn't run

℡╲_俬逩灬. 提交于 2019-12-02 17:30:31

I think the best solution for the Compatibility package is to override the AsyncTaskLoader.onStartLoading method.

e.g.

@Override
protected void onStartLoading() {
  if(dataIsReady) {
    deliverResult(data);
  } else {
    forceLoad();
  }
}

This is exactly a fix but it should work. I am pretty sure the compatibility library is broken. Try this:

getLoaderManager().initLoader(0, null, this).forceLoad();
KitKat

Cheok Yan Cheng is absolutely right:

Checking for takeContentChanged seems an important step too.

If you write your method like this:

protected void onStartLoading() {
    forceLoad();
}

you ''ll notice that when a child activity comes up and then you return to the parent one, onStartLoading (and so loadInBackground) are called again!

What can you do? Set an internal variable (mContentChanged) to true inside the constructor; then check this variable inside onStartLoading. Only when it's true, start loading for real:

package example.util;

import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;

public abstract class ATLoader<D> extends AsyncTaskLoader<D> {

    public ATLoader(Context context) {
        super(context);
        // run only once
        onContentChanged();
    }

    @Override
    protected void onStartLoading() {
        // That's how we start every AsyncTaskLoader...
        // -  code snippet from  android.content.CursorLoader  (method  onStartLoading)
        if (takeContentChanged()) {
            forceLoad();
        }
    }
}

Looking at discussion at https://code.google.com/p/android/issues/detail?id=14944, checking for takeContentChanged seems to be important step too.

protected void onStartLoading() {
    if (mCursor != null) {
        deliverResult(mCursor);
    }
    if (takeContentChanged() || mCursor == null) {
        forceLoad();
    }
}

I took the source code of CursorLoader from android framework, and wrote a CustomTaskLoader<T> class to ease the job.

https://github.com/Palatis/danbooru-gallery-android/blob/new_api/DanbooruGallery/src/main/java/tw/idv/palatis/danboorugallery/android/content/CustomTaskLoader.java

you basically implement these two functions:

public abstract T runTaskInBackground(CancellationSignal signal);
public abstract void cleanUp(T oldResult);

see the usage in the activities and fragments, for example this one: (well my code just ignores the CancellationSignal, it's a TODO in my list, but you're free to use it.)

https://github.com/Palatis/danbooru-gallery-android/blob/new_api/DanbooruGallery/src/main/java/tw/idv/palatis/danboorugallery/PostListFragment.java

return new CustomTaskLoader<Cursor>(getActivity().getApplicationContext()) 
{
    @Override
    public Cursor runTaskInBackground(CancellationSignal signal)
    {
        return SiteSession.getAllPostsCursor(PostListAdapter.POST_COLUMNS);
    }

    @Override
    public void cleanUp(Cursor oldCursor)
    {
        if (!oldCursor.isClosed())
            oldCursor.close();
    }
}

I have had the same problem after migrating from CursorLoader to AsyncTaskLoader.

documentation says: Subclasses of Loader<D> generally must implement at least onStartLoading(), onStopLoading(), onForceLoad(), and onReset().

AsyncTaskLoader extends Loader but not implements onStartLoading(), onStopLoading(), onReset(). You must implement it by yourself!

@davidshen84 proposed good solution. I only added checking for takeContentChanged.

@Override
protected void onStartLoading() {
    try {
        if (data != null) {
            deliverResult(data);
        }
        if (takeContentChanged() || data == null) {
            forceLoad();
        }

        Log.d(TAG, "onStartLoading() ");
    } catch (Exception e) {
        Log.d(TAG, e.getMessage());
    }
}

Using forceLoad() is ok (not a bad practice). See what documentation says:
You generally should only call this when the loader is started - that is, isStarted() returns true.

I was still having the problem that loading of data was not called. I finally removed the AsyncTaskLoader (the support library version) and used only AsyncTask (not from support library) to do the job. And it worked.

It could be enough for your needs too.

Description and example: http://developer.android.com/reference/android/os/AsyncTask.html.

You have to extend the class AsyncTask.

The method doInBackground will do the work and in the method onPostExecute you will get the result. For starting the AsyncTask, you will call the method execute on its instance. See the link.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!