Android: LoaderCallbacks.OnLoadFinished appelé deux fois
j'ai remarqué une situation étrange en utilisant des chargeurs et des Fragments Android. Quand j'invoque LoaderManager.initLoader () après changement d'orientation onLoadFinished n'est pas appelé (bien que la documentation suggère que je devrais être préparé pour cela) mais il est appelé deux fois après cela. Voici le lien pour poster dans les groupes google qui décrivent la même situation https://groups.google.com/forum/?fromgroups#!topic/android-developers / aA2vHYxSskU . J'ai écrit un exemple de demande dans laquelle je seulement init Chargeur simple Fragment.onActivityCreated() pour vérifier si cela arrive et il ne. Quelqu'un l'a remarqué?
8 réponses
vous pouvez placer la méthode initLoader() dans le rappel onResume() de votre Fragment; alors onLoadFinished() du chargeur ne sera plus appelé deux fois.
@Override
public void onResume()
{
super.onResume();
getLoaderManager().initLoader(0, null, this);
}
ce problème s'est manifesté pour moi avec un curseur retournant un curseur qui était déjà fermé:
android.database.StaleDataException: Attempted to access a cursor after it has been closed.
je suppose que c'est un bug ou un oubli. En déplaçant initLoader () dans onResume may work, ce que j'ai pu faire était d'enlever le chargeur quand j'en ai fini avec lui:
pour démarrer le chargeur (dans mon onCreate):
getLoaderManager().initLoader(MUSIC_LOADER_ID, null, this);
puis après que j'en ai fini avec elle (essentiellement à la fin de onLoadFinished)
getLoaderManager().destroyLoader(MUSIC_LOADER_ID);
cela semble se comporter comme prévu, pas d'appels supplémentaires.
si, au point d'appel, l'appelant est dans son état de départ, et demandé chargeur existe déjà et a généré ses données, rappel onLoadFinished(Chargeur, D)
je vous suggère d'implémenter quelque chose comme la fonction onStartLoading à ce sample
pour un test rapide, vous pouvez essayer:
@Override protected void onStartLoading() {
forceLoad();
}
cette fonction loadInBackground de lancement puis onLoadFinished in Fragment.
de toute façon, si vous ajoutez un code, j'essaierai de vous aider.
j'ai résolu le problème d'onLoadFinished étant appelé deux fois comme ceci. Dans ton Fragment.onActivityCreated() init votre Chargeur comme ce
if (getLoaderManager().getLoader(LOADER_ID) == null) {
getLoaderManager().initLoader(LOADER_ID, bundle, loaderCallbacks);
} else {
getLoaderManager().restartLoader(LOADER_ID, bundle, loaderCallbacks);
}
ici loaderCallbacks implémente vos callbacks de Loader habituels
private LoaderManager.LoaderCallbacks<T> loaderCallbacks
= new LoaderManager.LoaderCallbacks<T>() {
@Override
public Loader<T> onCreateLoader(int id, Bundle args) {
...
...
}
@Override
public void onLoadFinished(Loader<T> loader, T data) {
...
...
}
@Override
public void onLoaderReset(Loader<T> loader) {
...
...
}
};
le problème est qu'il a appelé deux fois:
1. à partir de Fragment.onStart
2. de FragmentActivity.onStart
la seule différence est celle du Fragment.onStart il vérifie si mLoaderManager != NULL. Ce que cela signifie est que si vous appelez getLoadManager avant onStart, comme dans onActivityCreated, il obtiendra/créera le gestionnaire de charge et il sera appelé. Pour éviter cela, vous devez appeler plus tard, comme dans onResume.
en appelant initLoader
de onActivityCreated
vous pouvez détecter la rotation:
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState == null) {
// fresh new fragment, not orientation/config change
getLoaderManager().initLoader(YOUR_LOADER_ID, null, mCallbacks);
}
...
}
de cette façon, le chargeur se comporte comme prévu résultant en appel simple onLoadFinished
.
Il n'est plus appelé rotation, donc si vous voulez les données du chargeur, vous pouvez les garder dans votre fragment, par exemple en remplaçant onSaveInstanceState
.
Edit:
Je viens de réaliser que onLoadFinished
ne sera pas appelé si la rotation a lieu pendant le loadInBackground
du chargeur . Pour corriger cela, vous devez toujours appeler initLoader
après la rotation si les données du chargeur ne sont pas encore disponibles.
Espère que ça aide.
vous pouvez également comparer l'objet de données dans onLoadFinished(Loader loader, Object data). Si l'objet de données correspond à celui que vous avez déjà, vous pouvez tout simplement ne rien faire quand onLoadFinished est appelé. Par exemple:
public void onLoadFinished(Loader loader, Object data) {
if(data != null && mData != data){
//Do something
}
}