1

I will come clean immediately by admitting that I don't understand Interfaces. I believe that I followed the process laid out in https://developer.android.com/training/basics/fragments/communicating.html. In section Define an Interface, I declare and define the required interface NewDate:

public class DatePickerFragment extends DialogFragment {
    NewDate mCallback;
    private static final String TAG = "DatePickerFragment";
    public Date date;

    private DatePicker mDatePicker;

    //interface implemented by DatePicker Activity
    public interface NewDate{
        public void UpdateDate(Date date);
    }

I implement it in the calling Activity as discussed in section Implement the Interface:

public class DatePickerActivity extends SingleFragmentActivity implements DatePickerFragment.NewDate {
    private final String TAG = "DatePickerActivity";
    private static final int REQUEST_DATE = 0;

    @Override
    protected Fragment createFragment() {
        Log.d(TAG, "Entered createFragment");
        Intent intent = getIntent();
        Date date = (Date) intent.getSerializableExtra(EXTRA_DATE);
        Log.d(TAG,"date = " + date);
        UUID id = (UUID) intent.getSerializableExtra(EXTRA_ID);
        Log.d(TAG, "crime ID is " + id);
        return DatePickerFragment.newInstance(date);
    }

    public void UpdateDate(Date date) {
        Log.d(TAG, "Entered UpdateDate");
        Log.d(TAG, "Date is " + date);
        Toast.makeText(getApplicationContext(),"Clicked OK to update date!", Toast.LENGTH_SHORT).show();
        return;
    }
}

Ignore the fact that returning date might be wrong, the problem is that the code never makes it here.

As shown the following method in DatePickerFragment is called when the user clicks the OK button to deliver the event to the parent DatePickerActivity and the onAttach method is performed when the DatePickerFragment attaches to DatePickerActivity:

    public class DatePickerFragment extends DialogFragment {

   ...

    private void sendResult(int resultCode, Date date){
        Log.d(TAG, "Entered sendResult");
        Log.d(TAG, "resultCode is " + resultCode);
        Log.d(TAG, "Date passed in to sendResult is " + date);

        if (getTargetFragment() == null) {
            if (mCallback != null){
            mCallback.UpdateDate(date);
            return;
            } else {
                Log.d(TAG, "mCallback is null");
                return;
            }

    ...

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        Log.d(TAG, "Entered onAttach");
        try {
            Log.d(TAG, "Trying to create new mCallback");
            mCallback = (NewDate) date;
            Log.d(TAG, "mCallback is " + mCallback);
        } catch (ClassCastException e){
            throw new ClassCastException(date.toString() + " must implement NewDate");
        }

The following is the LogCat output as a result of the code running after I run the code:

DatePickerActivity: Entered createFragment
DatePickerActivity: date = Mon Oct 23 15:24:38 CDT 2017
DatePickerActivity: crime ID is a205fce6-9a38-4c40-9dce-ba651c281752
DatePickerFragment: Entered newInstance
DatePickerFragment: Date is Mon Oct 23 15:24:38 CDT 2017
DatePickerFragment: id is 16842960
DatePickerFragment: Entered onAttach
DatePickerFragment: Trying to create new mCallback
DatePickerFragment: mCallback is null
DatePickerFragment: Entered onCreateView
DatePickerFragment: Date passed to DatePickerFragment is: Mon Oct 23 15:24:38 CDT 2017
DatePickerFragment: Set date in calendar
DatePickerFragment: year is 2017
DatePickerFragment: month is 9
DatePickerFragment: day is 23
DatePickerFragment: Entered onActivityCreated
DatePickerFragment: Entered onStart
DatePickerFragment: Entered onResume
DatePickerFragment: You clicked OK!
DatePickerFragment: onClick: year is 2017
DatePickerFragment: onClick: month is 9
DatePickerFragment: onClick: day is 31
DatePickerFragment: Dialog date is Tue Oct 31 00:00:00 CDT 2017
DatePickerFragment: Entered sendResult
DatePickerFragment: resultCode is -1
DatePickerFragment: Date passed in to sendResult is Tue Oct 31 00:00:00 CDT 2017
DatePickerFragment: mCallback is null

If you align the code's Log.d messages, you'll note that UpdateDate in DatePickerActivity is never accessed because mCallback is null. I thought that mCallback would not be null after onAttach, but it is still null. I've read other web pages, such as http://simpledeveloper.com/how-to-communicate-between-fragments-and-activities/ and http://techblogon.com/communication-between-activity-and-fragment-example/, that make me think that I've fulfilled the Interface requirements. However, I obviously haven't.

So, can anyone explain either what I missed on those web pages or provide a link to one that explains what I'm missing?

Daniel Nugent
  • 43,104
  • 15
  • 109
  • 137
Jeff
  • 431
  • 4
  • 16

1 Answers1

0

You need to assign mCallback to the activity that hosts your fragment and implements the DatePickerFragment.NewDate interface:

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    Log.d(TAG, "Entered onAttach");
    try {
        Log.d(TAG, "Trying to create new mCallback");
        //modified:
        if (context instanceof DatePickerActivity){
            mCallback = (DatePickerActivity) context; 
        }
        Log.d(TAG, "mCallback is " + mCallback);
    } catch (ClassCastException e){
        throw new ClassCastException(date.toString() + " must implement NewDate");
    }
}
Daniel Nugent
  • 43,104
  • 15
  • 109
  • 137
  • Daniel, you're a genius! That did it. However, in my reading of doing this I didn't see anything that would make me think of your suggestion. I need to understand interfaces. – Jeff Oct 24 '17 at 13:55
  • Check is set! Your suggestion points me to things that I need to understand, such as checking the context. It makes sense now that I see your if statement, the context of the Fragment is its Activity. That didn't sink in from the Fragment to Activity communication pages that I had read. Thanks for the clarity. – Jeff Oct 24 '17 at 14:40