How to send data from DialogFragment to a Fragment?
Solution 1:
NOTE: aside from one or two Android Fragment specific calls, this is a generic recipe for implementation of data exchange between loosely coupled components. You can safely use this approach to exchange data between literally anything, be it Fragments, Activities, Dialogs or any other elements of your application.
Here's the recipe:
- Create
interface
(i.e. namedMyContract
) containing a signature of method for passing the data, i.e.methodToPassMyData(... data);
. - Ensure your
DialogFragment
fullfils that contract (which usually means implementing the interface):class MyFragment extends Fragment implements MyContract {....}
- On creation of
DialogFragment
set your invokingFragment
as its target fragment by callingmyDialogFragment.setTargetFragment(this, 0);
. This is the object you will be talking to later. - In your
DialogFragment
, get that invoking fragment by callinggetTargetFragment();
and cast returned object to the contract interface you created in step 1, by doing:MyContract mHost = (MyContract)getTargetFragment();
. Casting lets us ensure the target object implements the contract needed and we can expectmethodToPassData()
to be there. If not, then you will get regularClassCastException
. This usually should not happen, unless you are doing too much copy-paste coding :) If your project uses external code, libraries or plugins etc and in such case you should rather catch the exception and tell the user i.e. plugin is not compatible instead of letting the app crash. - When time to send data back comes, call
methodToPassMyData()
on the object you obtained previously:((MyContract)getTargetFragment()).methodToPassMyData(data);
. If youronAttach()
already casts and assigns target fragment to a class variable (i.e.mHost
), then this code would be justmHost.methodToPassMyData(data);
. - Voilà. You just successfully passed your data from dialog back to invoking fragment.
Solution 2:
Here's another recipe without using any Interface. Just making use of the setTargetFragment
and Bundle
to pass data between DialogFragment and Fragment.
public static final int DATEPICKER_FRAGMENT = 1; // class variable
1.
Call the DialogFragment
as shown below:
// create dialog fragment
DatePickerFragment dialog = new DatePickerFragment();
// optionally pass arguments to the dialog fragment
Bundle args = new Bundle();
args.putString("pickerStyle", "fancy");
dialog.setArguments(args);
// setup link back to use and display
dialog.setTargetFragment(this, DATEPICKER_FRAGMENT);
dialog.show(getFragmentManager().beginTransaction(), "MyProgressDialog")
2.
Use the extra Bundle
in an Intent
in the DialogFragment
to pass whatever info back to the target fragment. The below code in Button#onClick()
event of DatePickerFragment
passes a String and Integer.
Intent i = new Intent()
.putExtra("month", getMonthString())
.putExtra("year", getYearInt());
getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, i);
dismiss();
3.
Use CalendarFragment
's onActivityResult()
method to read the values:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case DATEPICKER_FRAGMENT:
if (resultCode == Activity.RESULT_OK) {
Bundle bundle = data.getExtras();
String mMonth = bundle.getString("month", Month);
int mYear = bundle.getInt("year");
Log.i("PICKER", "Got year=" + year + " and month=" + month + ", yay!");
} else if (resultCode == Activity.RESULT_CANCELED) {
...
}
break;
}
}