Pour répondre à cette question, vous avez besoin de creuser dans le LoaderManager code.
Bien que la documentation pour LoaderManager elle-même n'est pas assez claire (ou il n'y aurait pas cette question), la documentation de LoaderManagerImpl, une sous-classe de l'abstrait LoaderManager, est beaucoup plus instructif.
initLoader
Appel à initialiser un ID particulier avec un Chargeur. Si cet ID est déjà
a un Chargeur associés avec elle, elle est restée inchangée, et de tous les précédents
rappels remplacé par les nouvelles. Si il n'y a pas
actuellement, un Chargeur pour l'ID, une nouvelle instance est créée et a commencé.
Cette fonction doit généralement être utilisé lorsqu'un composant est
lors de l'initialisation, pour s'assurer qu'un Chargeur, il s'appuie sur est créé. Cette
permet de ré-utiliser un Chargeur de données si il y en a déjà un,
de sorte que, par exemple, lorsqu'une Activité est re-créée après une
modification de la configuration, il n'a pas besoin de re-créer ses chargeurs.
restartLoader
Appel à re-créer le Chargeur associé à un ID spécifique. Si
il y a actuellement un Chargeur associé à cet IDENTIFIANT, il sera
annulé/arrêté/détruit tant que de besoin. Un nouveau Loader avec l'
étant donné les arguments seront créés et ses données livrés à vous une fois de
disponible.
[...] Après l'appel de cette fonction, les Chargeurs associés à ce code d'identification
sera considéré comme non valide, et vous ne recevrez pas d'autres données
les mises à jour à partir d'eux.
Il existe essentiellement deux cas de figure:
- Le chargeur avec l'id n'existe pas: les deux méthodes permettra de créer un nouveau chargeur donc il n'y a pas de différence
- Le chargeur avec l'id existe déjà: initLoader ne remplacer que les rappels passé comme paramètre, mais ne pas annuler ou arrêter le chargeur. Pour un CursorLoader cela signifie que le curseur reste ouverte et active (si c'était le cas avant le initLoader appel). restartLoader de l'autre coté, d'annuler, de s'arrêter et de détruire le chargeur (et fermer le sous-jacent de la source de données comme un curseur) et créer un nouveau chargeur (ce qui permettrait également de créer un nouveau curseur et de ré-exécuter la requête si le chargeur est un CursorLoader).
Voici le code simplifié pour les deux méthodes:
initLoader
LoaderInfo info = mLoaders.get(id);
if (info == null) {
// Loader doesn't already exist -> create new one
info = createAndInstallLoader(id, args, LoaderManager.LoaderCallbacks<Object>)callback);
} else {
// Loader exists -> only replace callbacks
info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
}
restartLoader
LoaderInfo info = mLoaders.get(id);
if (info != null) {
LoaderInfo inactive = mInactiveLoaders.get(id);
if (inactive != null) {
// does a lot of stuff to deal with already inactive loaders
} else {
// Keep track of the previous instance of this loader so we can destroy
// it when the new one completes.
info.mLoader.abandon();
mInactiveLoaders.put(id, info);
}
}
info = createAndInstallLoader(id, args, (LoaderManager.LoaderCallbacks<Object>)callback);
Comme nous pouvons le voir dans le cas où le chargeur n'existe pas (info == null) les deux méthodes permettra de créer un nouveau chargeur (info = createAndInstallLoader(...)).
Dans le cas où le chargeur existe déjà initLoader ne remplace les rappels (info.mCallbacks = ...) tout en restartLoader inactive de l'ancien chargeur (il sera détruit lorsque le nouveau chargeur termine son travail), puis crée un nouveau.
Ainsi dit, il est maintenant clair quand à l'utilisation initLoader et quand utiliser restartLoader et pourquoi il est logique d'avoir les deux méthodes.
initLoader est utilisé pour assurer une initialisé chargeur. Si aucun n'existe, un nouveau est créé, s'il en existe déjà un, il est ré-utilisé. Nous avons toujours utiliser cette méthode, SAUF si nous avons besoin d'un nouveau chargeur, car l'exécution de la requête a changé (pas les données sous-jacentes, mais la requête réelle, comme dans l'instruction SQL d'une CursorLoader), dans ce cas, nous allons appeler restartLoader.
L'Activité/Fragment de cycle de vie n'a rien à voir avec la décision d'utiliser l'une ou l'autre méthode (et il n'y a pas besoin de garder une trace des appels à l'aide d'un one-shot drapeau comme Simon suggéré)! Cette décision est prise uniquement sur la base du "besoin" d'un nouveau chargeur. Si nous voulons exécuter la même requête que nous utilisons initLoader, si nous voulons exécuter une autre requête, nous utilisons restartLoader.
On peut toujours utiliser restartLoader mais que serait inefficace. Après une rotation de l'écran ou si l'utilisateur quitte l'application et retourne par la suite pour la même Activité, nous avons l'habitude de vouloir montrer le même résultat de la requête, et donc la restartLoader inutilement re-créer le chargeur et de rejeter le sous-jacent (potentiellement coûteux) résultat de la requête.
Il est très important de comprendre la différence entre les données chargées et la "requête" pour charger les données. Supposons que nous utilisons un CursorLoader de l'interrogation d'une table pour les commandes. Si une nouvelle commande est ajoutée à la table de la CursorLoader utilise onContentChanged() pour les informer de l'interface utilisateur mise à jour et de montrer la nouvelle commande (pas besoin d'utiliser restartLoader dans ce cas). Si nous voulons afficher seulement les commandes ouvertes, nous avons besoin d'une nouvelle requête, et nous voudrions utiliser restartLoader retourner une nouvelle CursorLoader reflétant la nouvelle requête.
Est-il une relation entre les deux méthodes?
Ils partagent le code pour créer un nouveau Chargeur, mais ils font des choses différentes quand un chargeur existe déjà.
N'appelant restartLoader toujours faire appel à initLoader?
Non, il ne le fait jamais.
Puis-je appeler restartLoader sans avoir à appeler initLoader?
Oui.
Est-il sûr d'appel initLoader deux fois pour actualiser les données?
Il est possible d'appeler des initLoader deux fois, mais pas de données sera actualisée.
Quand dois-je utiliser l'un des deux et (important!) pourquoi?
Qui devrait (je l'espère) être clair, après mes explications ci-dessus.
Les modifications de Configuration
Un LoaderManager conserve son état à travers les changements de configuration (y compris les changements d'orientation de l') donc on pourrait penser il n'y a rien qui nous reste à faire. Réfléchir à nouveau...
Tout d'abord un LoaderManager ne conserve pas les rappels, donc si vous ne faites rien, vous n'aurez pas de recevoir des appels de vos méthodes de rappel comme onLoadFinished() et autres, et qui sera très probablement briser votre application.
Par conséquent, nous devons faire appel au moins initLoader pour restaurer les méthodes de rappel (un restartLoader est bien sûr possible aussi). La documentation états:
Si au moment de l'appel de l'appelant est dans son état démarré, et le
demandé chargeur existe déjà et a généré ses données,
rappel onLoadFinished(Chargeur, D) sera appelé immédiatement (à l'intérieur
de cette fonction) [...].
Cela signifie que si nous appelons initLoader après un changement d'orientation, nous aurons une onLoadFinished appelez tout de suite, car les données sont déjà chargés (en supposant tel était le cas avant le changement).
Alors que sonne tout droit vers l'avant, il peut être difficile (ne sommes-nous pas tous l'amour Android...).
Nous devons distinguer entre les deux cas:
- Gère les changements de configuration lui-même: c'est le cas pour des Fragments
que l'utilisation setRetainInstance(true) ou pour une Activité avec le
selon android:configChanges balise dans le manifeste. Ces
les composants de ne pas recevoir un onCreate appel après par exemple un
la rotation de l'écran, donc gardez à l'esprit d'appeler
initLoader/restartLoader dans un autre rappel de la méthode (par exemple, dans
onActivityCreated(Bundle)). Pour être en mesure d'initialiser le Chargeur(s),
le chargeur id doivent être stockées (par exemple, dans une Liste). Parce que
le composant est conservé à travers les modifications de la configuration, nous pouvons
juste une boucle sur l'existant chargeur id et appel initLoader(loaderid,
...).
- Ne gère pas les changements de configuration lui-même: Dans ce cas la
Les chargeurs peuvent être initialisés dans onCreate mais nous devons manuellement
conserver le chargeur id ou nous ne serons pas en mesure de faire le nécessaire
initLoader/restartLoader appels. Si les identifiants sont stockés dans un
Liste de tableaux, nous ferions un
outState.putIntegerArrayList(loaderIdsKey, loaderIdsArray)
onSaveInstanceState et de restaurer les id dans onCreate:
loaderIdsArray =
savedInstanceState.getIntegerArrayList(loaderIdsKey) avant de nous rendre
le initLoader appel(s).