Android
Chargeur
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);
...
}