Recherche…


Introduction

Loader est un bon choix pour éviter les fuites de mémoire si vous souhaitez charger des données en arrière-plan lorsque la méthode oncreate est appelée. Par exemple, lorsque nous exécutons Asynctask dans la méthode oncreate et que nous faisons pivoter l'écran pour que l'activité recrée exécute un autre AsyncTask à nouveau, deux Asyntask s'exécutant probablement en parallèle plutôt qu'un chargeur qui poursuivra le processus d'arrière-plan que nous avons exécuté auparavant.

Paramètres

Classe La description
LoaderManager Classe abstraite associée à une activité ou à un fragment pour gérer une ou plusieurs instances du chargeur.
LoaderManager.LoaderCallbacks Une interface de rappel permettant à un client d'interagir avec le LoaderManager.
Chargeur Une classe abstraite qui effectue un chargement asynchrone des données.
AsyncTaskLoader Chargeur abstrait qui fournit une tâche AsyncTask pour effectuer le travail.
CursorLoader Une sous-classe de AsyncTaskLoader qui interroge le ContentResolver et renvoie un curseur.

Remarques

Introduits dans Android 3.0, les chargeurs facilitent le chargement asynchrone de données dans une activité ou un fragment. Les chargeurs ont ces caractéristiques:

  • Ils sont disponibles pour chaque activité et fragment .
  • Ils fournissent un chargement asynchrone des données.
  • Ils surveillent la source de leurs données et fournissent de nouveaux résultats lorsque le contenu change.
  • Ils se reconnectent automatiquement au curseur du dernier chargeur lorsqu'ils sont recréés après un changement de configuration. Ainsi, ils n'ont pas besoin de ré-interroger leurs données.

Quand ne pas utiliser les chargeurs

Vous ne devez pas utiliser Loaders si vous avez besoin des tâches d'arrière-plan à effectuer. Android détruit les chargeurs avec les activités / fragments auxquels ils appartiennent. Si vous souhaitez effectuer certaines tâches, qui doivent être exécutées jusqu'à la fin, n'utilisez pas de chargeurs. Vous devriez utiliser les services pour ce genre de choses à la place.

AsyncTaskLoader de base

AsyncTaskLoader est un Loader abstrait qui fournit une AsyncTask pour effectuer le travail.

Voici quelques implémentations de base:

final class BasicLoader extends AsyncTaskLoader<String> {

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

    @Override
    public String loadInBackground() {
        // Some work, e.g. load something from internet
        return "OK";
    }

    @Override
    public void deliverResult(String data) {
        if (isStarted()) {
            // Deliver result if loader is currently started
            super.deliverResult(data);
        }
    }

    @Override
    protected void onStartLoading() {
        // Start loading
        forceLoad();
    }

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

    @Override
    protected void onReset() {
        super.onReset();

        // Ensure the loader is stopped
        onStopLoading();
    }
}

En règle générale, Loader est initialisé dans la méthode onCreate() l'activité ou dans le onActivityCreated() du fragment. En outre, l'activité ou le fragment implémente LoaderManager.LoaderCallbacks interface LoaderManager.LoaderCallbacks :

public class MainActivity extends Activity implements LoaderManager.LoaderCallbacks<String> {

    // Unique id for loader
    private static final int LDR_BASIC_ID = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Initialize loader; Some data can be passed as second param instead of Bundle.Empty
        getLoaderManager().initLoader(LDR_BASIC_ID, Bundle.EMPTY, this);
    }

    @Override
    public Loader<String> onCreateLoader(int id, Bundle args) {
        return new BasicLoader(this);
    }

    @Override
    public void onLoadFinished(Loader<String> loader, String data) {
        Toast.makeText(this, data, Toast.LENGTH_LONG).show();
    }

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

Dans cet exemple, lorsque le chargement est terminé, le toast avec le résultat sera affiché.

AsyncTaskLoader avec cache

Il est recommandé de mettre en cache les résultats chargés pour éviter le chargement multiple des mêmes données.
Pour invalider le cache onContentChanged() doit être appelé. Si loader a déjà été démarré, forceLoad() sera appelé, sinon (si loader à l'état arrêté), loader pourra comprendre le changement de contenu avec la takeContentChanged() de takeContentChanged() .

Remarque: onContentChanged() doit être appelé à partir du thread principal du processus.

Javadocs dit à propos de takeContentChanged ():

Prenez l'indicateur actuel indiquant si le contenu du chargeur a été modifié pendant son arrêt. Si c'était le cas, true est renvoyé et le drapeau est effacé.

public abstract class BaseLoader<T> extends AsyncTaskLoader<T> {

    // Cached result saved here
    private final AtomicReference<T> cache = new AtomicReference<>();

    public BaseLoader(@NonNull final Context context) {
        super(context);
    }

    @Override
    public final void deliverResult(final T data) {
        if (!isReset()) {
            // Save loaded result
            cache.set(data);
            if (isStarted()) {
                super.deliverResult(data);
            }
        }
    }

    @Override
    protected final void onStartLoading() {            
        // Register observers
        registerObserver();

        final T cached = cache.get();    
        // Start new loading if content changed in background
        // or if we never loaded any data
        if (takeContentChanged() || cached == null) {
            forceLoad();
        } else {
            deliverResult(cached);
        }
    }

    @Override
    public final void onStopLoading() {
        cancelLoad();
    }

    @Override
    protected final void onReset() {
        super.onReset();
        onStopLoading();
        // Clear cache and remove observers
        cache.set(null);
        unregisterObserver();
    }

    /* virtual */
    protected void registerObserver() {
        // Register observers here, call onContentChanged() to invalidate cache
    }

    /* virtual */
    protected void unregisterObserver() {
        // Remove observers
    }
}

Rechargement

Pour invalider vos anciennes données et redémarrer le chargeur existant, vous pouvez utiliser la méthode restartLoader() :

private void reload() {
    getLoaderManager().reastartLoader(LOADER_ID, Bundle.EMPTY, this);
}

Passer les paramètres à l'aide d'un ensemble

Vous pouvez passer des paramètres par Bundle:

Bundle myBundle = new Bundle();
myBundle.putString(MY_KEY, myValue);

Obtenez la valeur dans onCreateLoader:

@Override
public Loader<String> onCreateLoader(int id, final Bundle args) {
    final String myParam = args.getString(MY_KEY);
    ...
}


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow