问题
I have fragment that on a component click pop-ups DialogFragment. This dialog fragment holds list of options. When an option from list is selected I want to notify fragment so I can run fields update procedure. I did something like this
@Override
public void onClick(DialogInterface dialog, int item) {
updateSharedPreference(item);
Log.e("ProfilePersonaListDialog", "Click on dialog, inside onClick");
OnCloseListDialogListener act = (OnCloseListDialogListener) getActivity();
act.onDialogListSelection();
dismiss();
}
However this getActivity() calls on FragmentActivity and not the fragment that triggered the dialog fragment. I could kill currently open/running fragment and call a new instance that would get updated fields, but that is dirty solution that I would prefer to avoid.
Any suggestions how to go about this update of fragment once option selected in dialog fragment?.
回答1:
Just coming back with solution. My problem was actually forwarding current fragment getTag() string as parameter of show() for DialogFragment. If anyone interested here is working sample.
Create simple listener
public interface OnCloseListDialogListener {
public void onDialogListSelection();
}
Create new dialog that will extend DialogFragment
public class ListDialogFragment extends DialogFragment implements DialogInterface.OnClickListener {
private PersonaData[] mPersonaData;
private String[] mPersonaName;
private final String TAG;
public static ListDialogFragment newInstance(PersonaData[] personaData, String tag) {
ListDialogFragment dialog = new ListDialogFragment(personaData, tag);
Bundle bundle = new Bundle();
dialog.setArguments(bundle);
return dialog;
}
private ListDialogFragment(PersonaData[] personaData, String tag) {
this.mPersonaData = personaData.clone();
this.TAG = tag;
}
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setCancelable(true);
int style = DialogFragment.STYLE_NORMAL, theme = 0;
setStyle(style, theme);
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.dialog_title);
mPersonaName = getData();//Your own implementation here
builder.setNegativeButton("Cancel", this);
builder.setSingleChoiceItems(mPersonaName, -1, new SingleChoiceListener());
return builder.create();
}
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
private class SingleChoiceListener implements DialogInterface.OnClickListener {
@Override
public void onClick(DialogInterface dialog, int item) {
updateSharedPreference(item);
OnCloseListDialogListener act = (OnCloseListDialogListener) getFragmentManager().findFragmentByTag(TAG);
act.onDialogListSelection();
dismiss();
}
}
}
And then in fragment from which you wish to call this dialog do as bellow. DIALOG is just String constant I put there just dialog
SOME_CLICKABLE.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
FragmentManager manager = getFragmentManager();
ListDialogFragment dialog = ListDialogFragment.newInstance(mPersona, getTag());
dialog.show(manager, DIALOG);
}
});
回答2:
It is necessary in most cases that a Fragment
be aware that it is running under the context of an Activity
of some description and acceptable for the child Fragment to invoke a method on an interface implicitly implemented by the parent Activity (as demonstrated by the cast in your code snippet). When you get your references working as Tomasz points out you'll be golden.
However, :) to aid the re-usability of the dialog fragment I would suggest that you leverage BroadcastReceiver
s. A BroadcastReceiver simply broadcasts a message saying I did 'x'. The parent activity or in indeed any other top level component can then declare I am listening for 'x'. Once, the event has been fired in the dialog component, this event will be collected by the parent Activity's onReceive
where you can run the necessary code to update your fields.
On a personal level, I prefer this loose coupling over the casting interface approach since it forces me to think about the purpose of each Fragment and keep it modular.
If you want to give it a shot then have a read over the dev guide section on BroadcastReceivers and follow the follow steps;
Implement the
BroadcastReceiver
in your parent activity. Notice anonReceive
method is required to be implemented.Override the parent Activity's
onResume
method and register the the activity as a receiver of an event with intent action "blah". Something like;@Override protected void onResume() { super.onResume(); registerReceiver(this, new IntentFilter("blah")); }
Override the parent Activity's
onPause
method an unregister the activity as the receiver so as to avoid 'leaked receivers' (you'll find out).@Override protected void onPause() { super.onPause(); unregisterReceiver(deleteSpotReceiver); }
In your
DialogFragment
onClick
fire the event which your parent activity is 'listening' for.@Override public void onClick(DialogInterface dialog, int item) { updateSharedPreference(item); Log.e("ProfilePersonaListDialog", "Click on dialog, inside onClick"); final Intent intent = new Intent(); intent.setAction("blah"); getActivity().sendBroadcast(intent); dismiss(); }
The parent activity will collect the message and you can continue processing. Let me know if you decide to adopt that method.
回答3:
Just the way you did it above and add sth like that in your activity :
public void onDialogListSelection() {
AnotherFragment anotherFragment = (AnotherFragment) getSupportFragmentManager()
.findFragmentById(R.id.anotherFragment);
anotherFragment.customMethodToNotifyListHasBeenSelected();
}
Of course, if you are not use Support Library then call getFragmentManager
instead of getSupportFragmentManager
.
来源:https://stackoverflow.com/questions/10502937/update-fragment-on-dialog-fragment-option-selection