14

Sto migrando i miei dialoghi, attualmente utilizzando Activity.showDialog(DIALOG_ID);, per utilizzare il sistema DialogFragment come discusso nello android reference.Richiamata DialogFragment sul cambio di orientamento

C'è una domanda che nasce durante il mio sviluppo quando si utilizza callback per fornire qualche evento torna all'attività/frammento che ha aperto la finestra di dialogo:

ecco qualche codice di esempio di una semplice finestra di dialogo:

public class DialogTest extends DialogFragment { 

public interface DialogTestListener { 
    public void onDialogPositiveClick(DialogFragment dialog); 
} 

// Use this instance of the interface to deliver action events 
static DialogTestListener mListener; 

public static DialogTest newInstance(Activity activity, int titleId, int messageId) { 
    udateListener(activity); 
    DialogTest frag = new DialogTest(); 
    Bundle args = new Bundle(); 
    args.putInt("titleId", titleId); 
    args.putInt("messageId", messageId); 
    frag.setArguments(args); 
    return frag; 
} 

public static void udateListener(Activity activity) { 
    try { 
     // Instantiate the NoticeDialogListener so we can send events with it 
     mListener = (DialogTestListener) activity; 
    } catch (ClassCastException e) { 
     // The activity doesn't implement the interface, throw exception 
     throw new ClassCastException(activity.toString() + " must implement DialogTestListener"); 
    } 
} 


@Override 
public Dialog onCreateDialog(Bundle savedInstanceState) { 
    int titleId = getArguments().getInt("titleId"); 
    int messageId = getArguments().getInt("messageId"); 

    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 
    // dialog title 
    builder.setTitle(titleId); 
    // dialog message 
    builder.setMessage(messageId); 

    // dialog negative button 
    builder.setNegativeButton("No", new OnClickListener() { 
       public void onClick(DialogInterface dialog, int id) {}}); 
    // dialog positive button 
    builder.setPositiveButton("Yes", new OnClickListener() { 
     public void onClick(DialogInterface dialog, int id) { 
      mListener.onDialogPositiveClick(DialogTest.this); 
     }}); 

    // create the Dialog object and return it 
    return builder.create(); 
}} 

ed ecco qualche codice attività definendolo:

public class SomeActivity extends FragmentActivity implements DialogTestListener { 
private EditText mUserName; 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    // setup ui 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.ui_user_edit); 
    // name input 
    mUserName = (EditText) findViewById(R.id.userEdit_editTextName); 
} 

@Override 
public void onDialogPositiveClick(DialogFragment dialog) { 
    Log.d(TAG, this.toString()); 
    mUserName.setText(mUserName.getText() + "1"); 
} 

private void showDialog() { 
    DialogTest test = DialogTest.newInstance(SomeActivity.this, R.string.someTitleText, R.string.someMessageText); 
    test.show(getSupportFragmentManager(), "testDialog"); 
}} 

il codice è più o meno quello che si vede il riferimento. Il problema è che, una volta apportata una modifica dell'orientamento, quando viene visualizzata una finestra di dialogo, smette di funzionare come previsto -> A causa del ciclo di vita dell'attività, entrambe le attività e la finestra di dialogo vengono ricostruite e la finestra di dialogo non dispone della corretta riferimento alla nuova attività ricostruita.

ho aggiunto il seguente codice ai miei activitys metodo onResume:

@Override 
protected void onResume() { 
    super.onResume(); 
    DialogTest.udateListener(this); 
} 

Facendo questo, ho il comportamento previsto, e la finestra di dialogo invia gli eventi di nuovo alla nuova attività ricostruito quando un cambiamento di orientamento si è verificato.

La mia domanda è: Qual è la "migliore pratica" per gestire i callback tra il DialogFragment che è stato aperto da FragmentActivity durante un cambio di orientamento?

migliori saluti

+0

Sembra che tu sia caduto in una delle tante trappole del Frammento. Ho avuto lo stesso problema di te e sono riuscito a risolverlo leggendo questo eccellente articolo: http://code.hootsuite.com/orientation-changes-on-android/. –

risposta

6

Sì, questa è una trappola comune mi sto cadendo in tutto il tempo me stesso. Prima di tutto lasciatemi dire che la tua soluzione di chiamare DialogTest.udateListener() in onResume() sembra essere del tutto appropriata per me.

Un modo alternativo sarebbe quella di utilizzare un ResultReceiver che può essere serializzata come Parcelable:

public class DialogTest extends DialogFragment { 

public static DialogTest newInstance(ResultReceiver receiver, int titleId, int messageId) { 
    DialogTest frag = new DialogTest(); 
    Bundle args = new Bundle(); 
    args.putParcelable("receiver", receiver); 
    args.putInt("titleId", titleId); 
    args.putInt("messageId", messageId); 
    frag.setArguments(args); 
    return frag; 
} 

@Override 
public Dialog onCreateDialog(Bundle savedInstanceState) { 
    int titleId = getArguments().getInt("titleId"); 
    int messageId = getArguments().getInt("messageId"); 
    ResultReceiver receiver = getArguments().getParcelable("receiver"); 

    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 
    // dialog title 
    builder.setTitle(titleId); 
    // dialog message 
    builder.setMessage(messageId); 

    // dialog negative button 
    builder.setNegativeButton("No", new OnClickListener() { 
     public void onClick(DialogInterface dialog, int id) { 
      receiver.sendResult(Activity.RESULT_CANCEL, null); 
     }}); 
    // dialog positive button 
    builder.setPositiveButton("Yes", new OnClickListener() { 
     public void onClick(DialogInterface dialog, int id) { 
      receiver.sendResult(Activity.RESULT_OK, null); 
     }}); 

    // create the Dialog object and return it 
    return builder.create(); 
}} 

Poi si può gestire tutto nel ricevitore in questo modo:

protected void onReceiveResult(int resultCode, Bundle resultData) { 
    if (getActivity() != null){ 
     // Handle result 
    } 
} 

Partenza ResultReceiver doesn't survire to screen rotation per più dettagli. Quindi alla fine probabilmente hai ancora bisogno di ricablare lo ResultReceiver con il tuo Activity.L'unica differenza è che si scollega lo Activity dallo DialogFragment.

+0

Thx per il tuo contributo! Per ora userò la soluzione 'onResume()', quando avrò bisogno di un po 'di attività <-> Disaccoppiamento DialogFragment Daremo un'occhiata al ResultReceiver. – darksaga

+2

Estrarre il frammento # setRetainInstance (booleano) e leggere la documentazione. Questa è in realtà la soluzione che stiamo davvero cercando. Mentre l'attività viene ancora distrutta e ricreata, il frammento viene conservato e riutilizzato. Pertanto, il callback DialogTestListener punta ancora sull'oggetto corretto e non è necessario ricollegare i Fragments dopo la modifica della configurazione. –

+0

Il problema con questa soluzione è che se attivi "Non mantenere attività" apri la finestra di dialogo, quindi premi HOME e apri l'app dal launcher principale, la finestra di dialogo verrà ricreata e otterrai una BadParcelableException, sto lottando su questo. – David

-6

Un altro modo è che si può interrompere l'attività ottenendo ricreato. Devi dire a Android che gestirai il cambiamento dell'orientamento e Android non ricreerà la tua attività. È necessario aggiungere questo per la vostra attività al file manifest:

android:configChanges="keyboardHidden|orientation" 

Se non questo, allora è possibile utilizzare standard di onSaveInstanceState() per salvare il vostro stato e recuperare utilizzando savedInstanceState come raccomandato da Google.

Ecco guida ufficiale di Google per esso: http://developer.android.com/guide/components/activities.html#Lifecycle

Vai attraverso di essa, se non l'hai già. Ti aiuterà davvero nello sviluppo di Android.

+0

Non voglio interrompere l'attività che viene distrutta e ricreata durante un cambio di orientamento, funziona come previsto a questo proposito. Voglio solo conoscere la best practice per gestire i callback tra il DialogFragment che è stato aperto da FragmentActivity durante un cambio di orientamento. – darksaga

1

Innanzitutto, chiamare setTargetFragment da FragmentParent per iniziare dialogFragment. In dialogFragment utilizzare getTargetFragment per richiamare i frammenti e restituire i dati. Tutti i dati risultano sarà excute in onactivityresult di FragmentParent

segui questo link: Receive result from DialogFragment

+0

Mentre questo è corretto, non fa nulla per una domanda. Perché un trasferimento di dati e il ripristino di una richiamata dopo la rotazione sono cose diverse. Ad esempio, nel callback posso aprire un'altra attività o effettuare una richiesta. – CoolMind

2

Mentre la soluzione di André funziona, una soluzione migliore è quello di ottenere l'attività aggiornata durante onAttach() nel vostro Fragment.

private DialogTestListener mListener; 

@Override 
public void onAttach(Activity activity) { 
    super.onAttach(activity); 
    mListener = (DialogTestListener) activity; 
} 

Con questa soluzione, non sarà necessario per passare il Activity in newInstance() più. Devi solo assicurarti che il FragmentFragment sia un DialogTestListener. Inoltre, non è necessario salvare lo stato come nella soluzione ResultReceiver.

8

C'è una soluzione migliore invece di utilizzare metodi e variabili statici perché funzionerebbe solo su un'istanza della finestra di dialogo. E 'meglio per memorizzare il callback come membro non static

private DialogTestListener mListener; 
public void setListener (DialogTestListener listener){ 
    mListener = listener; 
} 

Poi si dovrebbe mostrare il vostro dialogo con TAG come questo mDialogFragment.show(getSupportFragmentManager(), DIALOG_TAG);

E poi nel onResume metodo della vostra attività è possibile reimpostare il vostro ascoltatore

protected void onResume() { 
    super.onResume(); 
    mDialogFragment = (CMFilterDialogFrg) getSupportFragmentManager().findFragmentByTag(DIALOG_TAG); 
    if(mDialogFragment != null){ 
     mDialogFragment.setListener(yourListener) 
    } 
} 
+0

Grazie - questo metodo ha funzionato per me! La prima volta per me usare i frammenti di dialogo con un callback. Stavo lottando con questo per un po '- per fortuna ho visto questo post. Ero quasi lì ma questo post ha aiutato a raggiungere una soluzione +1! –

+0

Jason Long offre la soluzione migliore se chiami la finestra di dialogo da un'attività, cuasodayleo offre la soluzione migliore se la chiami da un frammento e questa è la soluzione migliore se devi affrontare entrambi gli scenari. – natario