The best practice solution to pass data between a Fragment
and an Activity
is to use the listener pattern.
Implementing the listener pattern in the Fragment
First we need to define an interface. We add a method called onDateSet()
with a Date
parameter. It will be used to pass the Date
back to the Activity
:
public interface DatePickerFragmentListener {
public void onDateSet(Date date);
}
I recommend you nest this interface inside of the DatePickerFragment
like this:
public class DatePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener {
public interface DatePickerFragmentListener {
public void onDateSet(Date date);
}
...
}
We need to add a member variable to the DatePickerFragment
to hold the reference to the listener. We also need getter and setter methods for the listener and a notify method to safely call the listener:
public class DatePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener {
private DatePickerFragmentListener datePickerListener;
public interface DatePickerFragmentListener {
public void onDateSet(Date date);
}
public DatePickerFragmentListener getDatePickerListener() {
return this.datePickerListener;
}
public void setDatePickerListener(DatePickerFragmentListener listener) {
this.datePickerListener = listener;
}
protected void notifyDatePickerListener(Date date) {
if(this.datePickerListener != null) {
this.datePickerListener.onDateSet(date);
}
}
...
}
It is best practice to use a static factory method to create new Fragment
instances. One of the many benefits of doing this besides just convenience is that you can define a method that sets up the Fragment
correctly - for example setting listeners, passing values to the Fragment
etc. - and you don't risk forgetting something or mixing something up later on. In our case it needs to set the DatePickerFragmentListener
:
public class DatePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener {
public static DatePickerFragment newInstance(DatePickerFragmentListener listener) {
DatePickerFragment fragment = new DatePickerFragment();
fragment.setDatePickerListener(listener);
return fragment;
}
...
}
Now the only thing still missing is that we need to call notifyDatePickerListener()
in the callback of the DatePicker
in the DatePickerFragment
:
@Override
public void onDateSet(DatePicker view, int year, int month, int day) {
Calendar c = Calendar.getInstance();
c.set(year, month, day);
Date date = c.getTime();
// Here we call the listener and pass the date back to it.
notifyDatePickerListener(date);
}
Using it in your Activity
In your Activity
we just need to call the newInstance()
method we added to create a new properly set up DatePickerFragment
. We also need to pass a DatePickerFragmentListener
into newInstance()
. I recommend you let your Activity
implement the DatePickerFragmentListener
interface:
public class MainActivity extends Activity implements DatePickerFragmentListener {
...
@Override
public void onDateSet(Date date) {
// This method will be called with the date from the `DatePicker`.
}
}
You just have to create a new instance of your DatePickerFragment
using the newInstance()
method and pass in the Activity
to make this work:
DatePickerFragment fragment = DatePickerFragment.newInstance(this);
And that's it! Implementing it this way might be 10 lines of code more, but it is a 100 times better solution.
I tested everything and it is working perfectly. I hope I could help you and if you have any other questions feel free to ask!