53

Ho iniziato a utilizzare DialogFragment, perché funzionano correttamente attraverso le modifiche di orientamento e roba. Ma c'è un brutto problema che ho incontrato.Modo corretto di ignorare DialogFragment mentre l'applicazione è in background

Ho AsyncTask che mostra l'avanzamento DialogFragment e lo elimina onPostExecute. Tutto funziona correttamente, tranne quando si verifica mentre l'applicazione è in background (dopo aver premuto il pulsante Home, ad esempio). Quindi ho ricevuto questo errore su DialogFragment che termina con "Can not perform this action after onSaveInstanceState". Doh. Le finestre di dialogo regolari funzionano bene. Ma non FragmentDialog.

Quindi mi chiedo, qual è il modo corretto di chiudere DialogFragment mentre l'applicazione è in background? Non ho lavorato molto con Fragments, quindi penso che mi manchi solo qualcosa.

+0

si veda anche [qui] (http://stackoverflow.com/questions/7992496/how-to-handle-asynctask-onpostexecute-when-paused-to-avoid-illegalstateexception) per bella soluzione utilizzando una pausa gestore – PJL

risposta

108

DialogFragment ha un metodo chiamato dismissAllowingStateLoss()

+7

Funziona solo se si utilizza: ['show (FragmentManager, tag)'] (http://developer.android.com/reference/android/app/DialogFragment.html#show (android.app.FragmentManager,% 20java .lang.String)), ma non quando si utilizza ['show (FragmentTransaction, tag)'] (http://developer.android.com/reference/android/app/DialogFragment.html#show (android.app.FragmentTransaction,% 20java.lang.String)) perché 'popBackStack' in' dismissInternal' chiama 'enqueueAction (..., allowStateLoss = false)' anche se abbiamo chiesto di consentire la perdita di stato. E lo fa in entrambe le versioni di framework e di supporto. – TWiStErRob

+0

http://stackoverflow.com/a/10261449/1815624 – CrandellWS

0

Una soluzione che potrebbe funzionare è l'impostazione di Fragment.setRetainInstance(true) nel dialogfragment, ma non è la soluzione più carina.

A volte ho notato che devo accodare le mie azioni di dialogo per consentire al framework di ripristinare prima lo stato. Se riesci a ottenere il Looper corrente (Activity.getMainLooper()) e a completare il wrapper in un gestore, puoi provare a passare il licenziamento sul retro della coda pubblicando un eseguibile su quella coda.

Spesso finisco per utilizzare un frammento separato che è retaininstance(true) che ha un ResultReceiver. Quindi trasmetto il destinatario dei risultati ai miei lavori e gestisco i callback nel suo onReceive (spesso come router per altri ricevitori). Ma potrebbe essere un po 'più di lavoro che vale la pena se si utilizzano attività asincrone.

8

Questo è quello che ho fatto (df == dialogFragment):

Assicurarsi che si chiama la finestra di dialogo in questo modo:

df.show(getFragmentManager(),"DialogFragment_FLAG"); 

Quando si desidera dismis finestra di make questo assegno:

if(df.isResumed()){ 
    df.dismiss(); 
} 
return; 

Assicurarsi di avere il seguente nel metodo onResume() del frammento (non df)

@Override 
public void onResume(){ 
    Fragment f= getFragmentManager().findFragmentByTag("DialogFragment_FLAG"); 
    if (f!= null) { 
    DialogFragment df = (DialogFragment) f; 
    df.dismiss(); 
    getFragmentManager().beginTransaction().remove(f).commit(); 
    } 
    super.onResume(); 
} 

In questo modo, la finestra di dialogo sarà licenziato se è visibile .. se non è visibile la finestra sta per essere dismisded prossimo il frammento diventa visibile (onResume) ...

+0

Questo sistema chiude sempre il frammento quando l'utente torna indietro, e se non hanno ancora letto la finestra di dialogo, ha appena lasciato l'app subito dopo la sua visualizzazione? – TWiStErRob

+0

ora posso dissimmettere dialogfragment da questo codice –

3

Questo è quello che ho dovuto fare per ottenere quello che vuoi: devo un'attività frammento su cui stavo mostrando una finestra frammento di nome fragment_RedemptionPayment che viene dichiarata globalmente a la cima. Il seguente codice archivia lo DialogFragment se veniva mostrato prima che l'attività vada in background e ritorni in primo piano.

 @Override 
     public void onResume() { 
      super.onResume();   
      if(fragment_RedemptionPayment.isVisible()){ 
       fragment_RedemptionPayment.dismiss(); 
      } 
}