30 votes

AsyncTaskLoader ne s'exécute pas

Je veux implémenter un AsyncTaskLoader dans mon projet en utilisant le Compatibility Package, j'ai donc suivi le manuel du Loader dans Android Docs.

Le problème est que le Loader ne fait rien, il semble loadInBackground() n'est jamais appelé

Une idée de ce qui ne va pas dans mon code ? ( ExpandableListFragment étend Fragment mais ne surcharge aucune méthode critique )

Merci :-)

/**EDIT :

J'ai réalisé (tardivement, je suis un crétin) que AsyncTaskLoader est une classe abstraite donc je dois la sous-classer... m(__)m Je laisse la question au cas où quelqu'un viendrait derrière moi, qui sait...

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

    }

}

63voto

davidshen84 Points 1836

Je pense que la meilleure solution pour le paquet Compatibilité est de remplacer l'option AsyncTaskLoader.onStartLoading (chargeur de tâches) méthode.

par exemple

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

8voto

dbaugh Points 120

Il s'agit exactement d'un correctif mais cela devrait fonctionner. Je suis presque sûr que la bibliothèque de compatibilité est cassée. Essayez ceci :

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

3voto

KitKat Points 311

Cheok Yan Cheng a tout à fait raison :

La vérification de takeContentChanged semble également être une étape importante.

Si vous écrivez votre méthode comme ceci :

protected void onStartLoading() {
    forceLoad();
}

vous remarquerez que lorsqu'une activité enfant s'affiche et que vous revenez ensuite à l'activité parent, onStartLoading (et donc loadInBackground ) sont à nouveau appelés !

Que pouvez-vous faire ? Définissez une variable interne ( mContentChanged ) à true dans le constructeur ; ensuite, vérifiez cette variable dans l'élément onStartLoading . Seulement quand c'est vrai, commencez à charger pour de vrai :

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();
        }
    }
}

1voto

Cheok Yan Cheng Points 11825

En regardant la discussion à https://code.google.com/p/Android/issues/detail?id=14944 en vérifiant que takeContentChanged semble être une étape importante aussi.

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

0voto

曾其威 Points 53

J'ai pris le code source de CursorLoader du cadre Android, et a écrit un CustomTaskLoader<T> pour faciliter le travail.

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

vous implémentez essentiellement ces deux fonctions :

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

voir l'usage dans les activités et les fragments, par exemple celui-ci : (en fait, mon code ignore simplement le CancellationSignal c'est un TODO dans ma liste, mais vous êtes libre de l'utiliser).

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();
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X