使用 Calendar.SATURDAY 作为一周的最后一天时,Holo 日历崩溃

Holo Calendar crashes when using Calendar.SATURDAY as last day of week

我正在使用 Holo Calendar library

代码量很大,所以我不能把它包含在这个线程中。希望有人会看到这个谁用过它,但是这个库是免费的,页面底部有一个 link 可以打开一个完整的项目。

您可以通过以下方式设置日历的开始和结束日期:

mMultiCalendarView.setFirstDayOfWeek(Calendar.MONDAY);
mMultiCalendarView.setLastDayOfWeek(Calendar.SUNDAY);

但这对我来说是一个看起来很奇怪的日历。一周的第一天是星期一,然后两个周末都是周末。我希望每个星期都在星期天到星期六。

我可以将一周的第一天设置为任何内容,没有问题,但以下行:

mMultiCalendarView.setLastDayOfWeek(Calendar.SATURDAY);

导致应用程序停止运行,无论是一周的第一天。它似乎处于无限循环中,日志猫不断吐出类似以下内容:

02-10 20:29:03.876    2143-2143/(appName) I/dalvikvm-heap﹕ Clamp target GC heap from 96.710MB to 96.000MB
02-10 20:29:03.876    2143-2143/(appName) D/dalvikvm﹕ GC_FOR_ALLOC freed 1272K, 8% free 90712K/98260K, paused 45ms, total 45ms

直到应用崩溃并出现以下内存警告:

FATAL EXCEPTION: main
java.lang.OutOfMemoryError

错误指向库中的以下行:

at com.vdesmet.lib.calendar.CalendarView.createHeaders(CalendarView.java:286)
at com.vdesmet.lib.calendar.CalendarView.initView(CalendarView.java:93)
at com.vdesmet.lib.calendar.AbstractCalendarView.onLayout(AbstractCalendarView.java:397)

分别是以下几行:

LINE 286:    headers.addView(header);
LINE  93:    createHeaders();
LINE 397:    initView();

抱歉,如果没有手头的图书馆,这一切都毫无意义。我已经梳理了每一行代码,以及处理一周中几天的每个循环,但我无法弄清楚这一点。

有没有人处理过这个问题,或者有没有人对导致崩溃的原因有任何想法(基于 this Github page 上可用的库)?

从源代码来看,错误似乎是由 do-while 循环无法到达的结束条件引起的,特别是 createHeaders():

中的 line 288-291
private void createHeaders() {

    ...

    final int firstDayOfWeek = mFirstDayOfWeek;
    final int lastDayOfWeek = mLastDayOfWeek;

    ...

    int dayOfWeek = firstDayOfWeek;

    do {

        ...

        // increment dayOfWeek, make sure it's a valid day
        dayOfWeek = dayOfWeek % 7;
        dayOfWeek++;
    } while(dayOfWeek != lastDayOfWeek + 1);

    ...

}

Calendar.SATURDAY 的值为 7,而不是开发人员预期的 6。 (准确的说是从Calendar.SUNDAY(1),Calendar.MONDAY(2),...到Calendar.SATURDAY(7)。

另一方面,dayOfWeek % 7只会return0-6,之后加1,你会得到1-7。但是循环的结束条件是dayOfWeek == lastDayOfWeek + 1。为Calendar.SATURDAY时为(7 + 1) == 8,超出范围。因此,循环不会结束,导致 OutOfMemoryError.

解决方案是将结束条件更改为 while(dayOfWeek != (lastDayOfWeek % 7 + 1)); 以确保 lastDayOfWeek 也从 1-7 换行。

附录

需要在 CalendarView.java:

内的 2 行应用更改
  • createHeaders()line 291:

    } while(dayOfWeek != (lastDayOfWeek % 7 + 1));
    
  • initView()line 119:

    while((currentDay.get(Calendar.MONTH) + 1) % MONTHS_IN_YEAR == currentMonth ||
            currentDay.get(Calendar.MONTH) == currentMonth ||
            currentDay.get(Calendar.DAY_OF_WEEK) != (lastDayOfWeek % 7 + 1)) {
    

归功于 pandes for follow-up on their GitHub's issue