Open yccheok opened 4 years ago
我遇到同样问题了,而且是3月1号之后突然大量出现,好奇怪
我看源码WeekView已处理了相关代码,不过MultiWeekView没处理,我出现了~ calendarview.MultiWeekView.onDraw + 47 (MultiWeekView.java:47)
我有些怀疑 getFirstCalendarStartWithMinCalendar 的正确性。
这种把 ONE_DAY = 1000 3600 24;
会有出错的可能性吗?尤其是在一些有 Day Light Saving 的国家?
蛮多国家的 Day Light Saving 是在三月发生的。再加上,三月是,突然我有蛮多用户面临奔溃。因此,我的猜测应该是 Day Light Saving?
https://en.wikipedia.org/wiki/Daylight_saving_time_by_country
可否考虑引进 implementation 'com.jakewharton.threetenabp:threetenabp:1.2.1' 处理 getFirstCalendarStartWithMinCalendar 计算?
我尝试验证我的猜测。我写了以下代码在 Desktop 执行。
package javaapplication2;
import java.util.TimeZone;
/**
*
* @author yccheok
*/
public class JavaApplication2 {
private static final long ONE_DAY = 1000 * 3600 * 24;
static Calendar getFirstCalendarStartWithMinCalendar(TimeZone timeZone, int minYear, int minYearMonth, int minYearDay, int week, int weekStart) {
java.util.Calendar date = java.util.Calendar.getInstance(timeZone);
date.set(minYear, minYearMonth - 1, minYearDay);//
long firstTimeMills = date.getTimeInMillis();//获得起始时间戳
long weekTimeMills = (week - 1) * 7 * ONE_DAY;
long timeCountMills = weekTimeMills + firstTimeMills;
date.setTimeInMillis(timeCountMills);
int startDiff = getWeekViewStartDiff(timeZone,
date.get(java.util.Calendar.YEAR),
date.get(java.util.Calendar.MONTH) + 1,
date.get(java.util.Calendar.DAY_OF_MONTH), weekStart);
timeCountMills -= startDiff * ONE_DAY;
date.setTimeInMillis(timeCountMills);
Calendar calendar = new Calendar();
calendar.setYear(date.get(java.util.Calendar.YEAR));
calendar.setMonth(date.get(java.util.Calendar.MONTH) + 1);
calendar.setDay(date.get(java.util.Calendar.DAY_OF_MONTH));
return calendar;
}
private static int getWeekViewStartDiff(TimeZone timeZone, int year, int month, int day, int weekStart) {
java.util.Calendar date = java.util.Calendar.getInstance(timeZone);
date.set(year, month - 1, day);//
int week = date.get(java.util.Calendar.DAY_OF_WEEK);
if (weekStart == 1) {
return week - 1;
}
if (weekStart == 2) {
return week == 1 ? 6 : week - weekStart;
}
return week == 7 ? 0 : week;
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
final TimeZone timeZone = TimeZone.getTimeZone("Europe/Berlin");
System.out.println(timeZone);
int dayOfWeek = 1;
for (int x=1000; x<=3000; x++) {
Calendar result = getFirstCalendarStartWithMinCalendar(timeZone, 1971, 1, 1, x, dayOfWeek);
System.out.println(result.getDay() + "/" + result.getMonth() + "/" + result.getYear());
java.util.Calendar date = java.util.Calendar.getInstance();
date.set(result.getYear(), result.getMonth()-1, result.getDay());
if (dayOfWeek != date.get(java.util.Calendar.DAY_OF_WEEK)) {
throw new java.lang.RuntimeException("ERROR");
}
}
dayOfWeek = 2;
for (int x=1000; x<=3000; x++) {
Calendar result = getFirstCalendarStartWithMinCalendar(timeZone, 1971, 1, 1, x, dayOfWeek);
System.out.println(result.getDay() + "/" + result.getMonth() + "/" + result.getYear());
java.util.Calendar date = java.util.Calendar.getInstance();
date.set(result.getYear(), result.getMonth()-1, result.getDay());
if (dayOfWeek != date.get(java.util.Calendar.DAY_OF_WEEK)) {
throw new java.lang.RuntimeException("ERROR");
}
}
dayOfWeek = 7;
for (int x=1000; x<=3000; x++) {
Calendar result = getFirstCalendarStartWithMinCalendar(timeZone, 1971, 1, 1, x, dayOfWeek);
System.out.println(result.getDay() + "/" + result.getMonth() + "/" + result.getYear());
java.util.Calendar date = java.util.Calendar.getInstance();
date.set(result.getYear(), result.getMonth()-1, result.getDay());
if (dayOfWeek != date.get(java.util.Calendar.DAY_OF_WEEK)) {
throw new java.lang.RuntimeException("ERROR");
}
}
}
}
还是没有办法验证我的猜测。以上代码看来执行无误。
我也粗略的测试以下的代码片段。
/**
* 生成周视图的7个item
*
* @param calendar calendar
* @param mDelegate mDelegate
* @param weekStart weekStart
* @return 生成周视图的7个item
*/
static List<Calendar> initCalendarForWeekView(Calendar calendar, CalendarViewDelegate mDelegate, int weekStart) {
java.util.Calendar date = java.util.Calendar.getInstance();//当天时间
date.set(calendar.getYear(), calendar.getMonth() - 1, calendar.getDay());
long curDateMills = date.getTimeInMillis();//生成选择的日期时间戳
int weekEndDiff = getWeekViewEndDiff(calendar.getYear(), calendar.getMonth(), calendar.getDay(), weekStart);
List<Calendar> mItems = new ArrayList<>();
date.setTimeInMillis(curDateMills);
Calendar selectCalendar = new Calendar();
selectCalendar.setYear(date.get(java.util.Calendar.YEAR));
selectCalendar.setMonth(date.get(java.util.Calendar.MONTH) + 1);
selectCalendar.setDay(date.get(java.util.Calendar.DAY_OF_MONTH));
if (selectCalendar.equals(mDelegate.getCurrentDay())) {
selectCalendar.setCurrentDay(true);
}
LunarCalendar.setupLunarCalendar(selectCalendar);
selectCalendar.setCurrentMonth(true);
mItems.add(selectCalendar);
for (int i = 1; i <= weekEndDiff; i++) {
date.setTimeInMillis(curDateMills + i * ONE_DAY);
Calendar calendarDate = new Calendar();
calendarDate.setYear(date.get(java.util.Calendar.YEAR));
calendarDate.setMonth(date.get(java.util.Calendar.MONTH) + 1);
calendarDate.setDay(date.get(java.util.Calendar.DAY_OF_MONTH));
if (calendarDate.equals(mDelegate.getCurrentDay())) {
calendarDate.setCurrentDay(true);
}
LunarCalendar.setupLunarCalendar(calendarDate);
calendarDate.setCurrentMonth(true);
mItems.add(calendarDate);
}
return mItems;
}
我调整不同的 weekStart,我发现返回的 weekEndDiff 都是 6。
如果我采用粗暴的方法,用
// int weekEndDiff = getWeekViewEndDiff(calendar.getYear(), calendar.getMonth(), calendar.getDay(), weekStart);
int weekEndDiff = 6;
是可行的方案吗?
是这部分代码的问题,现在库里的所有时间戳,比如周起始,天起始,小时和分钟是当前时间,所以在夏令时的时区计算就会有问题,我项目的crash集中在东部夏令时晚上11点30-12点之间,所以我通过将周起始、天起始之类的时间戳手动设置为中午12点来解决了这个问题
@HolenZhou
https://github.com/huanghaibin-dev/CalendarView/commits/master
作者已经在主干解决这问题。我会在这个月内尝试结合,看看有没啥问题。(虽然我还不知如何准确的复制这问题)
Sometimes, I will encounter the following crash in Firebase Crashlytics
May I know why it is so? Isn't the size for
mItems
should be either 0 or 7? In what situation, its size will become 1? IsinitCalendarForWeekView
will always return an array with size 7?