Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AsyncTaskLoader doesn't run

I want to implement an AsyncTaskLoader in my project using the Compatibility Package, so I followed the Loader manual in Android Docs.

The problem is that the Loader does nothing, it seems loadInBackground() is never called

Any idea of what's wrong in my code? (ExpandableListFragment extends Fragment,but doesn't override any critical method )

Thank you :-)

/**EDIT:

I realized (late, I'm a moron) that AsyncTaskLoader is an abstract class so I need to subclass it... m(__)m I leave the question in case someone comes here behind me, who knows...

public class AgendaListFragment extends ExpandableListFragment implements
        LoaderManager.LoaderCallbacks<JSONArray> {

    private TreeMap<Integer, ArrayList<Evento>> mItems = new TreeMap<Integer, ArrayList<Evento>>();
    private AgendaListAdapter mAdapter;
    private ProgressBar mProgressBar;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.fragment_agenda, container);
        mProgressBar = (ProgressBar) root.findViewById(R.id.loading);
        return root;

    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        mAdapter = new AgendaListAdapter(getActivity());
        setListAdapter(mAdapter);

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

    }

    @Override
    public Loader<JSONArray> onCreateLoader(int arg0, Bundle arg1) {
        mProgressBar.setVisibility(View.VISIBLE);
        return new AsyncTaskLoader<JSONArray>(getActivity()) {
            @Override
            public JSONArray loadInBackground() {

                return getDataFromService(AgendaServices.LISTADO_MES);

            }

        };
    }

    @Override
    public void onLoadFinished(Loader<JSONArray> loader, JSONArray data) {

        // Some stuff to turn JSONArray into TreeMap

        mProgressBar.setVisibility(View.GONE);
        mAdapter.setItems(mItems);

    }

    @Override
    public void onLoaderReset(Loader<JSONArray> arg0) {
        mAdapter.setItems(null);
        mProgressBar.setVisibility(View.VISIBLE);

    }

}
like image 573
Aitor Gómez Avatar asked Dec 22 '11 15:12

Aitor Gómez


3 Answers

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();
  }
}
like image 116
David S. Avatar answered Oct 24 '22 01:10

David S.


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();
like image 8
dbaugh Avatar answered Oct 24 '22 00:10

dbaugh


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();
        }
    }
}
like image 3
KitKat Avatar answered Oct 24 '22 02:10

KitKat