Wenn man Dialoge in Android benutzen will muss man sie als Fragment an die Activity anbinden.
Die beste Möglichkeit um zwischen Dialog und Activity oder Fragment (an die Activity angebunden, in dem Beispiel RecordDetailFragment) zu kommunizieren sind Callbacks.
Das interface EditDateDialogListener beschreibt 2 Funktionen:
public void onDialogPositiveClick(DialogFragment dialog);
public void onDialogNegativeClick(DialogFragment dialog);
In der Klasse die den Dialog anhängen möchte implementiert man das Interface EditDateDialogListener (public class RecordDetailFragment extends SherlockFragment implements EditDateDialogFragment.EditDateDialogListener).
Die Callbacks sorgen dafür, dass der gesamte Dialog an die Activity zurückgegeben und dort verwendet werden kann.
Diese werden abhängig vom gedrückten Button an die implementierende Klasse geschickt.
Das größte Problem ist die Verbindung von Dialog und angebundener Activity:
Die Activity wird neu erstellt, wenn das Gerät z.B. gedreht wird. Der Dialog schickt nun seine Daten an die nicht mehr vorhandene Activity.
Daher muss diese Verbindung konsistent gehalten werden. Dafür sorgt die setListener Methode, die aufgerufen werden muss sobald man den Dialog anhängt und bei jedem Drehen des Displays (in der onCreate methode implementiert).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | public class EditDateDialogFragment extends DialogFragment { // Use this instance of the interface to deliver action events EditDateDialogListener mListener = new EditDateDialogListener() { @Override public void onDialogPositiveClick(DialogFragment dialog) { // Should always overridden by interface implementing class } @Override public void onDialogNegativeClick(DialogFragment dialog) { // Should always overridden by interface implementing class } }; DatePicker mDatePicker; /* * The activity that creates an instance of this dialog fragment must * implement this interface in order to receive event callbacks. Each method * passes the DialogFragment in case the host needs to query it. */ public interface EditDateDialogListener { public void onDialogPositiveClick(DialogFragment dialog); public void onDialogNegativeClick(DialogFragment dialog); } public void setListener(EditDateDialogListener listener) { mListener = listener; } public static EditDateDialogFragment newInstance(int currentCategoryId) { EditDateDialogFragment p = new EditDateDialogFragment(); Bundle args = new Bundle(); args.putInt("currentRecordId", currentCategoryId); p.setArguments(args); return p; } @Override public void onCreate(Bundle savedInstanceState) { mCurrentRecordId = getArguments().getInt("currentRecordId"); super.onCreate(savedInstanceState); } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { LayoutInflater inflater = LayoutInflater.from(getActivity()); final View v = inflater.inflate(R.layout.fragment_dialog_edit_date, null); mDatePicker = (DatePicker) v.findViewById(R.id.dialog_edit_date); return new AlertDialog.Builder(getActivity()).setTitle("Set Date...").setView(v).setCancelable(true).setPositiveButton("Confirm", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Log.d("", "Dialog confirmed"); mListener.onDialogPositiveClick(EditDateDialogFragment.this); } }).setNegativeButton("Abort", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Log.d("", "Dialog abort"); mListener.onDialogNegativeClick(EditDateDialogFragment.this); dialog.cancel(); } }).create(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | public class RecordDetailFragment extends SherlockFragment implements EditDateDialogFragment.EditDateDialogListener { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) { // Update reference // Update reference EditDateDialogFragment attachedDialogFragment = (EditDateDialogFragment) getActivity().getSupportFragmentManager().findFragmentByTag("EditDateDialogFragment"); // "tag" is the string set as the tag for the dialog when you show it if (attachedDialogFragment != null) { // the dialog exists so update its listener attachedDialogFragment.setListener(this); } } } // Called somewhere in the fragment public void showDialog() { EditDateDialogFragment editDateFragment = EditDateDialogFragment.newInstance(recordId); editDateFragment.setListener((EditDateDialogListener) this); editDateFragment.show(getActivity().getSupportFragmentManager(), "EditDateDialogFragment"); } @Override public void onDialogPositiveClick(DialogFragment dialog) { Log.d("RecordDetailFragment", "Callback Dialog confirmed"); int year = ((EditDateDialogFragment) dialog).mDatePicker.getYear(); Log.d("RecordDetailFragment", "Year of DatePicker: " + year); } @Override public void onDialogNegativeClick(DialogFragment dialog) { Log.d("RecordDetailFragment", "Callback Dialog abort"); // TODO Auto-generated method stub } } |
Das Beispiel ist nicht ausreichend erklärt – am besten einbauen und mit dem Debugger durchsteppen.
Es gibt einen guten Guide von Android, der Dialogs erklärt. Speziell habe ich auf die Kommunikation verlinkt. Mein Beispiel unterscheidet sich nicht groß, bis auf das konsistent halten der Callbacks.
Android empfiehlt übrigens solche Abhängigkeiten mit Callbacks zu realisieren.
Außerdem benutzte ich die ActionBarSherlock Library – deshalb die veränderten Activity-Klassen.
Eine falsche Implementierung des Dialogs kann man in der App AdAway sehen. Lädt man die host Einträge herunter erscheint nach Fertigstellung ein Dialog. Dreht man das Gerät verschwindet der Dialog. Offensichtlich besteht keine konsistente Verbindung zwischen Activity und Dialog, die bei uns die setListener übernimmt. Ich kenne den Code nicht und weiß nicht ob Callbacks verwendet wurden, jedoch verhält es sich so, wenn man die Verbindung nicht konsistent hält. Getestet in der AdAway Version 2.0 (39)
Danke, ist eine gute Erklärung. Mir ist nur nicht klar, wie die MainActivity aussehen muss.
Am liebsten hätte ich soviel wie möglich in Klassen verpackt, damit ich nicht so viel Code in der jeder
Activity habe. Vielleicht hast Du auch ein komplettes Beispiel bereit.
Warum ist das nur so kompliziert, in anderen Umgebungen ist das ein 3-Zeiler 🙁
Vielleicht gelingt es mir das Ganze in Design Patterns zu realisieren.
LG
Hallo, das Benutzen der Klasse ist einfach: Zunächst implementierst du das Interface (hier EditDateDialogFragment.EditDateDialogListener) des Dialogs in deiner Activity oder deinem Fragment, anschließend erstellst du einen Dialog wie folgt (z.B. bei Klick auf einen Button):
wobei ich gerade bemerke, dass die Benutzung doch bereits im Artikel beschrieben ist.
Jedoch muss ich auch sagen, dass dieser Artikel schon älter ist und ich seither wenig mit Android zu tun hatte. Andererseits habe ich ein paar Libraries (wie Sweet Alert Dialog oder Android Styled Dialogs) mitbekommen, die sich dem Erstellen von Dialogen annehmen. Außerdem wurde AppCompatDialog in die Android Support Library eingepflegt. Der beste Startpunkt sollten die genannten Libraries + Open Source Apps als Referenz sein. Zum finden von Libraries empfehle ich https://android-arsenal.com/.
LG No3x