2016-05-08 24 views
11

Ho un'attività principale A che utilizza un CursorLoader per interrogare un DB. Questo Creo nell'attività onCreate() metodo:Perché CursorLoader onLoaderReset() viene chiamato dopo la rotazione del dispositivo?

protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    ... 
    getSupportLoaderManager().initLoader(LOADER_MEASUREMENTS, null, A.this); 
} 

esercizi A implementa anche i 3 callback per l'CursorLoader:

public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) 
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) 
public void onLoaderReset(Loader<Cursor> loader) 

Quando ruoto dispositivo, vedo i metodi del ciclo di vita corretti eseguire:

A.onPause() 
A.onStop() 
A.onDestroy()   
A.onCreate()  <-- re-connect to existing loader, onCreateLoader() not called 
A.onLoadFinished() 
A.onStart() 
A.onResume() 

Quindi apro una sotto-attività B e ruoto il mio dispositivo. Quando finisco B e ritorno all'attività A vedo il seguente periodo:

B.onPause() 
     A.onLoaderReset()  <- why does this run? 
     A.onDestroy()   
     A.onCreate() 
     A.onCreateLoader()  <- now runs as loader is null 
     A.onStart() 
     ... 

Perché il mio ripristino loader perché avevo attività B aperto e fatto una rotazione dispositivo? Giusto per aggiungere che l'attività B non ha nulla a che fare con il DB o con il CursorLoader.

+2

[Questa domanda] (http://stackoverflow.com/questions/15897547/loader-unable-to-retain-itself-during-certain-configuration-change?lq=1) e le domande collegate sono correlate. Forse puoi trovare qualcosa che potrebbe aiutarti. –

+0

Grazie George - questa domanda tratta esattamente lo stesso problema che sto avendo. Sembra che potrebbe essere dovuto a Support Loader Manager. – MickeyR

+2

Questo [collegamento] (https://code.google.com/p/android/issues/detail?id=183783) afferma che questo è/sarà corretto in v24. – MickeyR

risposta

1

Sembra che questo abbia a che fare con lo LoaderManager e non mantenga lo stato di attività.

Il LoaderManager è gestito da android.app.FragmentHostCallback e void doLoaderStop(boolean retain) in questa classe sembra fare la differenza. A seconda dell'argomento sarà retain() o stop() i suoi caricatori.

Quando si modifica la configurazione nell'attività A (ruotando lo schermo) l'attività viene distrutta e immediatamente ricreata. In ActivityThread#handleRelaunchActivity() il valore mChangingConfigurations dell'attività viene impostato su true. Questo è importante, perché quando ci si ferma l'attività sul cambiamento della configurazione, questo viene chiamato in Activity:

final void performStop() { 
    mDoReportFullyDrawn = false; 
    mFragments.doLoaderStop(mChangingConfigurations /*retain*/); 
    // ... 
} 

si può provare a scendere più in profondità ciò che accade — l'installazione di Android dovrebbe avere le fonti e grep è impressionante per fare questo — ma mi limiterò a riassumere il resto.

Diniego: non ho accuratamente verificare le seguenti, ma questo è quello che ho capito che sta accadendo.

Come si può vedere sopra, quando l'attività è considerata adatta per rilancio sarà mantenere le pale anziché arresto loro. Quando si ruota l'attività A, i caricatori vengono mantenuti. Quando si ruota l'attività B, l'attività B viene ricreata immediatamente, mentre l'attività A viene appena distrutta. Contrariamente a prima, i caricatori verranno fermati.

I caricatori interrotti possono essere semplicemente distrutti e ricreati come previsto dal LoaderManager, e questo è ciò che sta accadendo al tuo.

Se si vuole dare una buona occhiata voi stessi, check out:

  • app/LoaderManager o v4/app/LoaderManager
  • app/FragmentHostCallback
  • Activity e ActivityThread
1

Si può semplicemente impostare un punto di interruzione all'interno A .onLoaderReset() ed esegui l'app in modalità di debug per vedere la traccia dello stack per la risoluzione dei problemi usando qualcosa g come:

class A extends Activity implements LoaderManager.LoaderCallbacks 
{ 
    @Override 
    public void onLoaderReset(Loader loader) 
    { 
     try 
     { 
      // Constructs a new Exception that includes the current stack trace. 
      throw new Exception(); 
     } 
     catch (Exception e) 
     { 
      Log.d("TAG", Log.getStackTraceString(e)); 
     } 
    } 
} 
3

ho controllato il LoaderManagersource code troverete questo metodo:

/** 
    * Stops and removes the loader with the given ID. If this loader 
    * had previously reported data to the client through 
    * {@link LoaderCallbacks#onLoadFinished(Loader, Object)}, a call 
    * will be made to {@link LoaderCallbacks#onLoaderReset(Loader)}. 
    */ 
    public abstract void destroyLoader(int id); 

Sembra che si caricatore viene distrutta durante la rotazione dello schermo (a causa dei cambiamenti di configurazione). Il LoaderManager chiama internamente il metodo destroyLoader che a sua volta chiama il metodo di richiamata onLoaderReset.

Problemi correlati