14

Ich migriere meine Dialoge, die derzeit Activity.showDialog(DIALOG_ID); verwenden, um das DialogFragment-System zu verwenden, wie in der android reference beschrieben.DialogFragment-Callback bei Orientierungsänderung

Es ist eine Frage, die während meiner Entwicklung entstand, als Rückrufe mit ein Ereignis zurück auf die Aktivität/Fragment zu liefern, die den Dialog geöffnet:

Hier einige Beispiel-Code eines einfachen Dialog:

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(); 
}} 

und hier ist etwas Code Aktivität nannte es:

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"); 
}} 

Der Code ist ziemlich viel, was Sie die Referenz. Problem ist, dass, sobald Sie eine Orientierungsänderung machen, wenn ein Dialog angezeigt wird, es nicht mehr wie erwartet funktioniert -> Aufgrund des Aktivitätslebenszyklus werden sowohl die Aktivität als auch der Dialog neu aufgebaut, und der Dialog hat nun nicht mehr die richtige Verweis auf die neu erstellte Aktivität.

Ich habe den folgenden Code in meine activitys onResume Methode:

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

dies tun, ich das erwartete Verhalten zu bekommen, und der Dialog sendet Ereignisse zurück an die neue rebuilt Aktivität, wenn eine Orientierungsänderung aufgetreten.

Meine Frage ist: Was ist die 'Best Practice', um die Rückrufe zwischen dem DialogFragment zu behandeln, das von einer FragmentActivity während einer Orientierungsänderung geöffnet wurde?

Mit freundlichen Grüßen

+0

Hört sich an, als wären Sie in eine der vielen Fallstricke gefallen. Ich hatte das gleiche Problem wie Sie und ich konnte es beheben, während Sie durch diesen ausgezeichneten Artikel lesen: http://code.hootsuite.com/orientation-changes-on-android/. –

Antwort

6

Ja, das ist eine gewöhnliche Falle, in die ich selbst die ganze Zeit hineinfalle. Lassen Sie mich zunächst sagen, dass Ihre Lösung des Anrufs DialogTest.udateListener() in onResume() scheint mir völlig angemessen zu sein.

Eine alternative Möglichkeit wäre, eine ResultReceiver zu verwenden, die als Parcelable serialisiert werden kann:

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

Check out ResultReceiver doesn't survire to screen rotation für:

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(); 
}} 

Dann sind Sie alles in den Receiver wie folgt umgehen kann mehr Details. Am Ende müssen Sie wahrscheinlich noch die ResultReceiver mit Ihrer Activity verdrahten.Der einzige Unterschied ist, dass Sie die Activity von der DialogFragment entkoppeln.

+0

Thx für Ihre Eingabe! Für den Moment verwende ich die 'onResume()' Lösung, sobald ich etwas Aktivität benötige <-> DialogFragment Entkopplung Ich sehe mir den ResultReceiver an. – darksaga

+2

Schauen Sie sich Fragment # setRetainInstance (boolean) an und lesen Sie die Dokumentation durch. Das ist eigentlich die Lösung, nach der wir wirklich suchen. Während die Aktivität immer noch zerstört und neu erstellt wird, wird das Fragment beibehalten und wiederverwendet. Daher zeigt der Callback-DialogTestListener immer noch auf das richtige Objekt und Sie müssen die Fragmente nach der Konfigurationsänderung nicht neu verkabeln. –

+0

Das Problem mit dieser Lösung ist, dass, wenn Sie aktivieren "Aktivitäten nicht behalten" den Dialog öffnen, dann drücken Sie auf STARTSEITE und öffnen Sie die App aus dem Home Launcher, der Dialog wird neu erstellt und Sie erhalten eine BadParcelableException, ich habe Probleme darauf. – David

-6

Eine andere Möglichkeit ist, dass Sie aufhören kann die Aktivität neu erstellt zu werden. Sie müssen Android sagen, dass Sie die Orientierungsänderung selbst vornehmen und Android Ihre Aktivität nicht neu erstellen wird. Sie müssen dies Ihre Manifest-Datei für Ihre Aktivität hinzuzufügen:

android:configChanges="keyboardHidden|orientation" 

Wenn nicht diese, dann können Sie Standard-onSaveInstanceState() verwenden Ihren Zustand zu speichern und wiederherzustellen savedInstanceState Verwendung von Google empfohlen.

Hier offizielle Guide von Google für sie: http://developer.android.com/guide/components/activities.html#Lifecycle

durch sie gehen, wenn Sie nicht bereits haben. Es wird Ihnen wirklich bei der Android-Entwicklung helfen.

+0

Ich möchte nicht verhindern, dass die Aktivität während einer Orientierungsänderung zerstört und neu erstellt wird, sie funktioniert in dieser Hinsicht wie erwartet. Ich möchte nur die beste Vorgehensweise kennen, um die Rückrufe zwischen dem DialogFragment zu behandeln, das von einer FragmentActivity während einer Orientierungsänderung geöffnet wurde. – darksaga

1

Rufen Sie zuerst setTargetFragment von FragmentParent an, um dialogFragment zu starten. In dialogFragment verwenden Sie getTargetFragment, um Fragment zurückzurufen und Daten zurückzugeben. Alle Daten führen excute in onactivityresult von FragmentParent

folgen Sie diesem Link: Receive result from DialogFragment

+0

Während das richtig ist, hat es keine Frage. Weil eine Übertragung von Daten und das Wiederherstellen eines Rückrufs nach der Rotation unterschiedliche Dinge sind. Zum Beispiel kann ich im Callback eine andere Aktivität öffnen oder eine Anfrage stellen. – CoolMind

2

Während André-Lösung funktioniert, eine bessere Lösung ist die aktualisierte Aktivität während onAttach() in Ihrem Fragment zu bekommen.

private DialogTestListener mListener; 

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

Mit dieser Lösung werden Sie nicht mehr die Activity in newInstance() passieren müssen. Sie müssen nur sicherstellen, dass der Activity Besitzer Ihres Fragment ist ein DialogTestListener. Sie müssen den Status auch nicht wie in der ResultReceiver-Lösung speichern.

8

Es gibt eine bessere Lösung anstelle von statischen Methoden und Variablen, da es nur für eine Instanz Ihres Dialogs funktioniert. Es ist besser, Ihren Rückruf als nicht statisches Element speichern

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

Dann sollten Sie Ihren Dialog zeigen TAG mit wie diese mDialogFragment.show(getSupportFragmentManager(), DIALOG_TAG);

Und dann in onResume Methode Ihrer Aktivität können Sie Ihre Zuhörer

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

Danke - diese Methode hat für mich funktioniert! Das erste Mal, dass ich Dialog Fragments mit einem Callback benutze. Ich habe eine Weile damit gerungen - Gott sei Dank habe ich diesen Beitrag gesehen. Ich war selbst fast da, aber dieser Beitrag hat geholfen, eine Lösung +1 zu erreichen! –

+0

Jason Long bietet die beste Lösung, wenn Sie den Dialog von einer Aktivität aus aufrufen. Cuasodayleo bietet die beste Lösung, wenn Sie ihn aus einem Fragment aufrufen. Dies ist die beste Lösung, wenn Sie beide Szenarien bewältigen müssen. – natario

Verwandte Themen