Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update fragment on dialog fragment option selection

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?.

like image 279
peter_budo Avatar asked May 08 '12 16:05

peter_budo


2 Answers

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);
    }
});
like image 187
peter_budo Avatar answered Nov 09 '22 15:11

peter_budo


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 BroadcastReceivers. 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;

  1. Implement the BroadcastReceiver in your parent activity. Notice an onReceive method is required to be implemented.

  2. 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"));
    }
    
  3. 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);
    }
    
  4. 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.

like image 41
BrantApps Avatar answered Nov 09 '22 17:11

BrantApps