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é?

52
demandé sur LukaszS 0000-00-00 00:00:00

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);
}
36
répondu Bogdan Zurac 2013-01-25 14:40:34

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.

24
répondu Matt 2014-03-04 21:17:42

documentation initLoader dit,

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.

6
répondu jperera 2016-08-31 11:38:56

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) {
        ...
        ...
    }
};
4
répondu Amrendra Kumar 2016-03-06 07:10:22

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.

3
répondu vovkab 2014-11-07 22:11:56

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.

2
répondu kiruwka 2015-02-05 13:48:45

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
        }
}
0
répondu Amer Meer 2015-04-15 16:21:18

puisque toute la recherche de ce sujet finit inévitablement ici, je voulais juste

0
répondu