为了解决这个问题,在 DatePickerDialog 实例化之前为 minDate 创建一个时间戳:
private void showDatePicker(){
long now = System.currentTimeMillis();
DatePickerDialog datePickerDialog = new DatePickerDialog(
getActivity(), this, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH));
datePickerDialog.getDatePicker().setMinDate(now);
datePickerDialog.show();
}
发生此崩溃的原因是在 API21 之前的 CalendarView 和 API21 的 calendarViewMode == MODE_HOLO 中存在错误。
虽然setMinDate 包含一个用注释突出显示的更正:
public void setMinDate(long minDate) {
...
mMinDate.setTimeInMillis(minDate);
// make sure the current date is not earlier than
// the new min date since the latter is used for
// calculating the indices in the adapter thus
// avoiding out of bounds error
Calendar date = mAdapter.mSelectedDate;
if (date.before(mMinDate)) {
mAdapter.setSelectedDay(mMinDate);
}
// reinitialize the adapter since its range depends on min date
mAdapter.init();
setSelectedDay 中的检查仅比较 mMinDate 和 mSelectedDate 的日期准确性:
public void setSelectedDay(Calendar selectedDay) {
if (selectedDay.get(Calendar.DAY_OF_YEAR) == mSelectedDate.get(Calendar.DAY_OF_YEAR)
&& selectedDay.get(Calendar.YEAR) == mSelectedDate.get(Calendar.YEAR)) {
return;
}
mSelectedDate 和mMinDate 指向同一天,因此mSelectedDate 将保持不变(即处于错误状态mSelectedDate < mMinDate)。
然后控制流将运行到mAdapter.init,然后进入getWeeksSinceMinDate。在此函数中,mMinDate 和 mSelectedDate 的比较将以毫秒精度执行:
private int getWeeksSinceMinDate(Calendar date) {
if (date.before(mMinDate)) {
throw new IllegalArgumentException("fromDate: " + mMinDate.getTime()
+ " does not precede toDate: " + date.getTime());
}
因为mSelectedDate 在mMinDate 之前的几毫秒内初始化,所以会发生崩溃。
在较新的实现中,此代码已被重写,因此 API21+ 缺少此问题。