onDateChanged method does not seem to work

2019-05-01 11:09发布

问题:

this is my first post and I am trying to create a very simple tasker app, however I am having issues with (what seems to be) the onDateChanged method. It seems that it does not implement the changes even though the dialog pops up normally. There are no errors in the log and i double checked various solutions with similar functionalities, but i could not find something relevant. (minSDK 16, Target 21)

Thanks a lot in advance and I am sorry if it is something obvious.

 
public class DatePickerFragment extends DialogFragment {

    public static final String EXTRA_DATE = "thanoschatz.com.annastodolist.date";

    private Date mDate;

    public static DatePickerFragment newInstance(Date mDate) {
        Bundle args = new Bundle();
        args.putSerializable(EXTRA_DATE, mDate);

        DatePickerFragment fragment = new DatePickerFragment();
        fragment.setArguments(args);

        return fragment;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        mDate = (Date) getArguments().getSerializable(EXTRA_DATE);


        Calendar calendar = Calendar.getInstance();
        calendar.setTime(mDate);
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH);
        int day = calendar.get(Calendar.DAY_OF_MONTH);

        View v = getActivity().getLayoutInflater().inflate(R.layout.dialog_date, null);

        DatePicker datePicker = (DatePicker) v.findViewById(R.id.dialog_date_datepicker);
        datePicker.init(year, month, day, new DatePicker.OnDateChangedListener() {
            @Override
            public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {

                mDate = new GregorianCalendar(year, monthOfYear, dayOfMonth).getTime();


                getArguments().putSerializable(EXTRA_DATE, mDate);
            }
        });

        return new AlertDialog.Builder(getActivity())
                .setView(v) //
                .setTitle(R.string.date_picker_title) //
                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        sendResult(Activity.RESULT_OK);
                    }
                })
                .create();
    }

    private void sendResult(int resultCode) {
        if (getTargetFragment() == null) return;

        Intent intent = new Intent();
        intent.putExtra(EXTRA_DATE, mDate);

        getTargetFragment().onActivityResult(getTargetRequestCode(), resultCode, intent);
    }
}
 

public class ToDoFragment extends Fragment {
    public static final String EXTRA_TODO_ID = "thanoschatz.com.annastodolist.todo_id";
    private static final String DIALOG_DATE = "date";
    private static final int REQUEST_DATE = 0;

    private ToDo mToDo;
    private EditText mTitleField;
    private Button mDateButton;
    private CheckBox mDoneCheckBox;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
        UUID toDoId = (UUID)getArguments().getSerializable(EXTRA_TODO_ID);
        mToDo= ToDoLab.get(getActivity()).getToDo(toDoId);
    }



    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_todo, container, false);
        wireTitleField(view);
        wireDateButton(view);
        wireSolvedCheckBox(view);
        return  view;
    }




    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
        if (resultCode != Activity.RESULT_OK) {
            return;
        }
        if (requestCode == REQUEST_DATE) {
            Date mDate = (Date)intent.getSerializableExtra(DatePickerFragment.EXTRA_DATE);
            mToDo.setDate(mDate);
           
        }
    }

    public ToDoFragment(){

    }

    
    public static ToDoFragment newInstance(UUID mId) {
        Bundle args = new Bundle();
        args.putSerializable(EXTRA_TODO_ID, mId);

        ToDoFragment fragment = new ToDoFragment();
        fragment.setArguments(args);

        return fragment;
    }

  

    private void wireDateButton(View view) {
        SimpleDateFormat dateFormatter = getSimpleDateFormat();
        mDateButton = (Button)view.findViewById(R.id.toDo_date);
        updateDate(dateFormatter);

        mDateButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                FragmentManager fragmentManager = getFragmentManager();
                DatePickerFragment datePicker = DatePickerFragment.newInstance(mToDo.getDate());
                datePicker.setTargetFragment(ToDoFragment.this, REQUEST_DATE);
                datePicker.show(fragmentManager, DIALOG_DATE);
            }
        });
    }
}

回答1:

There is also another way to get it to work under 5.0 and keeping your DatePicker in Calendar mode. What you can do is set to listen to the click changes on the dialog, and update your date reference. If by any chance your closing dialog handler notices that the last button clicked was "cancel" then simply ignore the change...

private String dateString; //last date saved.
    private String clickedDate; //last date clicked on DatePicker
    private DatePicker datePicker;

@Override
    protected void onDialogClosed(boolean shouldSave) {
        if (shouldSave && this.clickedDate != null) {
            updateDate(this.clickedDate);
            this.clickedDate = null;
        }
    }

@Override
    public void onDateChanged(DatePicker view, int year, int month, int day)       {
        Calendar selected = new GregorianCalendar(year, month, day);
        this.clickedDate = formatter().format(selected.getTime());
    }

    @Override
    public void onClick(DialogInterface dialog, int which) {
        super.onClick(dialog, which);
        datePicker.clearFocus();
        onDateChanged(datePicker, datePicker.getYear(), datePicker.getMonth(),
                datePicker.getDayOfMonth());
        onDialogClosed(which == DialogInterface.BUTTON_NEGATIVE);
    }

private void updateDate(String s) {
dateString = s;
}

This is where the idea came from https://github.com/bostonandroid/DatePreference/blob/master/DatePreference/src/org/bostonandroid/datepreference/DatePreference.java



回答2:

You're running your app under Android 5.0, right? I've found that under 5.0 a DatePicker will not call the OnDateChanged() method when it's in its default CalendarView mode, but it will do so if it's Spinners mode. Your code should work if the DatePicker is shown as spinners.

The only way I've found to force a 5.0 DatePicker into Spinners mode is to include the following in the xml code defining the DatePicker:

android:datePickerMode="spinner"

Lollipop seems to ignore any android:CalendarViewShown="false" directives as well as all DatePicker.setCalendarViewShown(false) calls in Java code. The datePickerMode xml directive is supported only in API 21, but any device running at a lower API level will just ignore it, so your code will still run on older versions of Android. Keep the CalendarViewShown="false" directive in your xml code, however, if you want the DatePicker to be spinners on a pre-5.0 device.



回答3:

Use DatePickerDialog instead:

return new DatePickerDialog(getActivity(), this, year, month, day);

Your class declaration should look like this:

public class DatePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener {

You will need to implement OnDateSet method:

@Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
    mDate = new GregorianCalendar(year, monthOfYear, dayOfMonth).getTime();
    getArguments().putSerializable(EXTRA_DATE, mDate);

    sendResult(Activity.RESULT_OK);
}

Or you can set your theme to Holo.Light which seems to support DatePicker OnDateChanged events. In your manifest file:

<application android:label="@string/app_name"
             android:icon="@drawable/ic_launcher"
             android:theme="@android:style/Theme.Holo.Light">

Or you can lower your minimum API level, this will set Holo theme by default:

<uses-sdk android:minSdkVersion="15" />


回答4:

This is my answer that can simply solve this question:

public class MyDatePickerDialog extends DatePickerDialog
{

    public MyDatePickerDialog(Context context, OnDateSetListener callBack, int year,
                              int monthOfYear, int dayOfMonth)
    {
        super(context, callBack, year, monthOfYear, dayOfMonth);
    }


    @TargetApi(11)
    @Override
    public void onClick(DialogInterface dialog, int which)
    {
        getDatePicker().clearFocus();
        super.onClick(dialog, which);
    }
}