I have a fragment that opens a Dialogfragment
to get user input (a string, and an integer). How do I send these two things back to the fragment?
Here is my DialogFragment:
public class DatePickerFragment extends DialogFragment {
String Month;
int Year;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
getDialog().setTitle(getString(R.string.Date_Picker));
View v = inflater.inflate(R.layout.date_picker_dialog, container, false);
Spinner months = (Spinner) v.findViewById(R.id.months_spinner);
ArrayAdapter<CharSequence> monthadapter = ArrayAdapter.createFromResource(getActivity(),
R.array.Months, R.layout.picker_row);
months.setAdapter(monthadapter);
months.setOnItemSelectedListener(new OnItemSelectedListener(){
@Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int monthplace, long id) {
Month = Integer.toString(monthplace);
}
public void onNothingSelected(AdapterView<?> parent) {
}
});
Spinner years = (Spinner) v.findViewById(R.id.years_spinner);
ArrayAdapter<CharSequence> yearadapter = ArrayAdapter.createFromResource(getActivity(),
R.array.Years, R.layout.picker_row);
years.setAdapter(yearadapter);
years.setOnItemSelectedListener(new OnItemSelectedListener(){
@Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int yearplace, long id) {
if (yearplace == 0){
Year = 2012;
}if (yearplace == 1){
Year = 2013;
}if (yearplace == 2){
Year = 2014;
}
}
public void onNothingSelected(AdapterView<?> parent) {}
});
Button button = (Button) v.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
getDialog().dismiss();
}
});
return v;
}
}
I need to send the data after the button click and before getDialog().dismiss()
Here is the fragment that data needs to be sent to:
public class CalendarFragment extends Fragment {
int Year;
String Month;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int position = getArguments().getInt("position");
String[] categories = getResources().getStringArray(R.array.categories);
getActivity().getActionBar().setTitle(categories[position]);
View v = inflater.inflate(R.layout.calendar_fragment_layout, container, false);
final Calendar c = Calendar.getInstance();
SimpleDateFormat month_date = new SimpleDateFormat("MMMMMMMMM");
Month = month_date.format(c.getTime());
Year = c.get(Calendar.YEAR);
Button button = (Button) v.findViewById(R.id.button);
button.setText(Month + " "+ Year);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
new DatePickerFragment().show(getFragmentManager(), "MyProgressDialog");
}
});
return v;
}
}
so once the user selects a date in the Dialogfragment
, it must return the month and year.
Then, the text on the button should change to the month and year specified by user.
This class was deprecated in API level 28. Use the Support Library DialogFragment for consistent behavior across all devices and access to Lifecycle.
you can set your args. class IntervModifFragment : DialogFragment(), ModContract. View { companion object { fun newInstance( plom:String,type:String,position: Int):IntervModifFragment { val fragment =IntervModifFragment() val args = Bundle() args. putString( "1",plom) args.
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:
interface
(i.e. named MyContract
) containing a signature of method for passing the data, i.e. methodToPassMyData(... data);
.DialogFragment
fullfils that contract (which usually means implementing the interface): class MyFragment extends Fragment implements MyContract {....}
DialogFragment
set your invoking Fragment
as its target fragment by calling myDialogFragment.setTargetFragment(this, 0);
. This is the object you will be talking to later.DialogFragment
, get that invoking fragment by calling getTargetFragment();
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 expect methodToPassData()
to be there. If not, then you will get regular ClassCastException
. 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.methodToPassMyData()
on the object you obtained previously: ((MyContract)getTargetFragment()).methodToPassMyData(data);
. If your onAttach()
already casts and assigns target fragment to a class variable (i.e. mHost
), then this code would be just mHost.methodToPassMyData(data);
.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;
}
}
Here's an approach that illustrates Marcin's answer implemented in kotlin.
1.Create an interface that have a method for passing data in your dialogFragment class.
interface OnCurrencySelected{
fun selectedCurrency(currency: Currency)
}
2.Add your interface in your dialogFragment constructor.
class CurrencyDialogFragment(val onCurrencySelected :OnCurrencySelected) :DialogFragment() {}
3.Now make your Fragment implement the interface you just created
class MyFragment : Fragment(), CurrencyDialogFragment.OnCurrencySelected {
override fun selectedCurrency(currency: Currency) {
//this method is called when you pass data back to the fragment
}}
4.Then to show your dialogFragment your just call
CurrencyDialogFragment(this).show(fragmentManager,"dialog")
. this
is the interface object you will be talking to, to pass data back to your Fragment.
5.When you want to sent data back to your Fragment you just call the method to pass data on the interface object your passed in dialogFragment constructor.
onCurrencySelected.selectedCurrency(Currency.USD)
dialog.dismiss()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With