From 1201893ee5a64c462cdcd47b2bb6509bd33dd21d Mon Sep 17 00:00:00 2001 From: Lai Kitman Date: Fri, 3 Mar 2017 14:30:07 +0800 Subject: [PATCH 1/3] update dependency --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 ++-- library/build.gradle | 8 ++++---- sample/build.gradle | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index 010afe941..b0d268b5b 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:1.3.0' + classpath 'com.android.tools.build:gradle:2.3.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1dbd8cc09..51c912da9 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Sep 19 19:16:06 BDT 2014 +#Fri Mar 03 14:28:32 CST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-2.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip diff --git a/library/build.gradle b/library/build.gradle index 8dc7eed88..321feca8d 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -5,17 +5,17 @@ repositories { } android { - compileSdkVersion 23 - buildToolsVersion "23.0.1" + compileSdkVersion 25 + buildToolsVersion "25.0.2" defaultConfig { minSdkVersion 9 - targetSdkVersion 23 + targetSdkVersion 25 } } dependencies { - compile 'com.android.support:appcompat-v7:23.1.1' + compile 'com.android.support:appcompat-v7:25.2.0' } apply from: 'https://raw.github.com/chrisbanes/gradle-mvn-push/master/gradle-mvn-push.gradle' \ No newline at end of file diff --git a/sample/build.gradle b/sample/build.gradle index 4ceeab2f1..e0d287af8 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -1,13 +1,13 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 23 - buildToolsVersion "23.0.1" + compileSdkVersion 25 + buildToolsVersion "25.0.2" defaultConfig { applicationId "com.alamkanak.weekview" minSdkVersion 9 - targetSdkVersion 23 + targetSdkVersion 25 versionCode 1 versionName "1.0" } @@ -22,6 +22,6 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile project(':library') - compile 'com.android.support:appcompat-v7:23.1.1' + compile 'com.android.support:appcompat-v7:25.2.0' compile 'com.squareup.retrofit:retrofit:1.9.0' } From 466b11846f591699431ed87abcb1fa4c7817b3c0 Mon Sep 17 00:00:00 2001 From: Lai Kitman Date: Fri, 3 Mar 2017 16:26:10 +0800 Subject: [PATCH 2/3] avoid new StaticLayout to save memory --- .../java/com/alamkanak/weekview/WeekView.java | 182 ++++++++++-------- .../com/alamkanak/weekview/WeekViewEvent.java | 175 ++++++++++++----- .../com/alamkanak/weekview/WeekViewUtil.java | 22 ++- .../weekview/sample/AsynchronousActivity.java | 8 +- 4 files changed, 259 insertions(+), 128 deletions(-) diff --git a/library/src/main/java/com/alamkanak/weekview/WeekView.java b/library/src/main/java/com/alamkanak/weekview/WeekView.java index da3fa71a0..e318bde30 100755 --- a/library/src/main/java/com/alamkanak/weekview/WeekView.java +++ b/library/src/main/java/com/alamkanak/weekview/WeekView.java @@ -93,8 +93,8 @@ private enum Direction { private Direction mCurrentFlingDirection = Direction.NONE; private ScaleGestureDetector mScaleDetector; private boolean mIsZooming; - private Calendar mFirstVisibleDay; - private Calendar mLastVisibleDay; + private final Calendar mFirstVisibleDay = Calendar.getInstance(); + private final Calendar mLastVisibleDay = Calendar.getInstance(); private boolean mShowFirstDayOfWeekFirst = false; private int mDefaultEventColor; private int mMinimumFlingVelocity = 0; @@ -497,6 +497,7 @@ protected void onDraw(Canvas canvas) { drawTimeColumnAndAxes(canvas); } + private static final Calendar sFirstVisibleDayCalendar = Calendar.getInstance(); private void calculateHeaderHeight(){ //Make sure the header is the right size (depends on AllDay events) boolean containsAllDayEvent = false; @@ -504,11 +505,12 @@ private void calculateHeaderHeight(){ for (int dayNumber = 0; dayNumber < mNumberOfVisibleDays; dayNumber++) { - Calendar day = (Calendar) getFirstVisibleDay().clone(); - day.add(Calendar.DATE, dayNumber); + sFirstVisibleDayCalendar.setTimeInMillis(mFirstVisibleDay.getTimeInMillis()); + sFirstVisibleDayCalendar.add(Calendar.DATE, dayNumber); for (int i = 0; i < mEventRects.size(); i++) { - if (isSameDay(mEventRects.get(i).event.getStartTime(), day) && mEventRects.get(i).event.isAllDay()) { + if (isSameDay(mEventRects.get(i).event.getStartTime(), sFirstVisibleDayCalendar.getTimeInMillis()) + && mEventRects.get(i).event.isAllDay()) { containsAllDayEvent = true; break; } @@ -544,6 +546,10 @@ private void drawTimeColumnAndAxes(Canvas canvas) { } } + private static final Calendar sOldFirstVisibleDay = Calendar.getInstance(); + private static final Calendar sIterateDay = Calendar.getInstance(); + private static final Calendar sNow = Calendar.getInstance(); + private void drawHeaderRowAndEvents(Canvas canvas) { // Calculate the available width for each day. mHeaderColumnWidth = mTimeTextWidth + mHeaderColumnPadding *2; @@ -608,8 +614,7 @@ else if (mNewHourHeight > mMaxHourHeight) float startPixel = startFromPixel; // Prepare to iterate for each day. - Calendar day = (Calendar) today.clone(); - day.add(Calendar.HOUR, 6); + sIterateDay.add(Calendar.HOUR, 6); // Prepare to iterate for each hour to draw the hour lines. int lineCount = (int) ((getHeight() - mHeaderHeight - mHeaderRowPadding * 2 - @@ -628,29 +633,30 @@ else if (mNewHourHeight > mMaxHourHeight) canvas.clipRect(mHeaderColumnWidth, mHeaderHeight + mHeaderRowPadding * 2 + mHeaderMarginBottom + mTimeTextHeight/2, getWidth(), getHeight(), Region.Op.REPLACE); // Iterate through each day. - Calendar oldFirstVisibleDay = mFirstVisibleDay; - mFirstVisibleDay = (Calendar) today.clone(); + sOldFirstVisibleDay.setTimeInMillis(mFirstVisibleDay.getTimeInMillis()); + mFirstVisibleDay.setTimeInMillis(today.getTimeInMillis()); mFirstVisibleDay.add(Calendar.DATE, -(Math.round(mCurrentOrigin.x / (mWidthPerDay + mColumnGap)))); - if(!mFirstVisibleDay.equals(oldFirstVisibleDay) && mScrollListener != null){ - mScrollListener.onFirstVisibleDayChanged(mFirstVisibleDay, oldFirstVisibleDay); + if(!mFirstVisibleDay.equals(sOldFirstVisibleDay) && mScrollListener != null){ + mScrollListener.onFirstVisibleDayChanged(mFirstVisibleDay, sOldFirstVisibleDay); } for (int dayNumber = leftDaysWithGaps + 1; dayNumber <= leftDaysWithGaps + mNumberOfVisibleDays + 1; dayNumber++) { // Check if the day is today. - day = (Calendar) today.clone(); - mLastVisibleDay = (Calendar) day.clone(); - day.add(Calendar.DATE, dayNumber - 1); + long todayTime = today.getTimeInMillis(); + sIterateDay.setTimeInMillis(todayTime); + mLastVisibleDay.setTimeInMillis(todayTime); + sIterateDay.add(Calendar.DATE, dayNumber - 1); mLastVisibleDay.add(Calendar.DATE, dayNumber - 2); - boolean sameDay = isSameDay(day, today); + boolean sameDay = isSameDay(sIterateDay, today); // Get more events if necessary. We want to store the events 3 months beforehand. Get // events only when it is the first iteration of the loop. if (mEventRects == null || mRefreshEvents || - (dayNumber == leftDaysWithGaps + 1 && mFetchedPeriod != (int) mWeekViewLoader.toWeekViewPeriodIndex(day) && - Math.abs(mFetchedPeriod - mWeekViewLoader.toWeekViewPeriodIndex(day)) > 0.5)) { - getMoreEvents(day); + (dayNumber == leftDaysWithGaps + 1 && mFetchedPeriod != (int) mWeekViewLoader.toWeekViewPeriodIndex(sIterateDay) && + Math.abs(mFetchedPeriod - mWeekViewLoader.toWeekViewPeriodIndex(sIterateDay)) > 0.5)) { + getMoreEvents(sIterateDay); mRefreshEvents = false; } @@ -658,18 +664,18 @@ else if (mNewHourHeight > mMaxHourHeight) float start = (startPixel < mHeaderColumnWidth ? mHeaderColumnWidth : startPixel); if (mWidthPerDay + startPixel - start > 0){ if (mShowDistinctPastFutureColor){ - boolean isWeekend = day.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || day.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY; + boolean isWeekend = sIterateDay.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || sIterateDay.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY; Paint pastPaint = isWeekend && mShowDistinctWeekendColor ? mPastWeekendBackgroundPaint : mPastBackgroundPaint; Paint futurePaint = isWeekend && mShowDistinctWeekendColor ? mFutureWeekendBackgroundPaint : mFutureBackgroundPaint; float startY = mHeaderHeight + mHeaderRowPadding * 2 + mTimeTextHeight/2 + mHeaderMarginBottom + mCurrentOrigin.y; if (sameDay){ - Calendar now = Calendar.getInstance(); - float beforeNow = (now.get(Calendar.HOUR_OF_DAY) + now.get(Calendar.MINUTE)/60.0f) * mHourHeight; + sNow.setTimeInMillis(System.currentTimeMillis()); + float beforeNow = (sNow.get(Calendar.HOUR_OF_DAY) + sNow.get(Calendar.MINUTE)/60.0f) * mHourHeight; canvas.drawRect(start, startY, startPixel + mWidthPerDay, startY+beforeNow, pastPaint); canvas.drawRect(start, startY+beforeNow, startPixel + mWidthPerDay, getHeight(), futurePaint); } - else if (day.before(today)) { + else if (sIterateDay.before(today)) { canvas.drawRect(start, startY, startPixel + mWidthPerDay, getHeight(), pastPaint); } else { @@ -698,13 +704,13 @@ else if (day.before(today)) { canvas.drawLines(hourLines, mHourSeparatorPaint); // Draw the events. - drawEvents(day, startPixel, canvas); + drawEvents(sIterateDay, startPixel, canvas); // Draw the line at the current time. if (mShowNowLine && sameDay){ float startY = mHeaderHeight + mHeaderRowPadding * 2 + mTimeTextHeight/2 + mHeaderMarginBottom + mCurrentOrigin.y; - Calendar now = Calendar.getInstance(); - float beforeNow = (now.get(Calendar.HOUR_OF_DAY) + now.get(Calendar.MINUTE)/60.0f) * mHourHeight; + sNow.setTimeInMillis(System.currentTimeMillis()); + float beforeNow = (sNow.get(Calendar.HOUR_OF_DAY) + sNow.get(Calendar.MINUTE)/60.0f) * mHourHeight; canvas.drawLine(start, startY + beforeNow, startPixel + mWidthPerDay, startY + beforeNow, mNowLinePaint); } @@ -726,21 +732,22 @@ else if (day.before(today)) { startPixel = startFromPixel; for (int dayNumber=leftDaysWithGaps+1; dayNumber <= leftDaysWithGaps + mNumberOfVisibleDays + 1; dayNumber++) { // Check if the day is today. - day = (Calendar) today.clone(); - day.add(Calendar.DATE, dayNumber - 1); - boolean sameDay = isSameDay(day, today); + sIterateDay.setTimeInMillis(today.getTimeInMillis()); + sIterateDay.add(Calendar.DATE, dayNumber - 1); + boolean sameDay = isSameDay(sIterateDay, today); // Draw the day labels. - String dayLabel = getDateTimeInterpreter().interpretDate(day); + String dayLabel = getDateTimeInterpreter().interpretDate(sIterateDay); if (dayLabel == null) throw new IllegalStateException("A DateTimeInterpreter must not return null date"); canvas.drawText(dayLabel, startPixel + mWidthPerDay / 2, mHeaderTextHeight + mHeaderRowPadding, sameDay ? mTodayHeaderTextPaint : mHeaderTextPaint); - drawAllDayEvents(day, startPixel, canvas); + drawAllDayEvents(sIterateDay, startPixel, canvas); startPixel += mWidthPerDay + mColumnGap; } } + private static final Calendar sDay = Calendar.getInstance(); /** * Get the time and date where the user clicked on. * @param x The x position of the touch event. @@ -756,15 +763,15 @@ private Calendar getTimeFromPoint(float x, float y){ dayNumber++) { float start = (startPixel < mHeaderColumnWidth ? mHeaderColumnWidth : startPixel); if (mWidthPerDay + startPixel - start > 0 && x > start && x < startPixel + mWidthPerDay){ - Calendar day = today(); - day.add(Calendar.DATE, dayNumber - 1); + sDay.setTimeInMillis(today().getTimeInMillis()); + sDay.add(Calendar.DATE, dayNumber - 1); float pixelsFromZero = y - mCurrentOrigin.y - mHeaderHeight - mHeaderRowPadding * 2 - mTimeTextHeight/2 - mHeaderMarginBottom; int hour = (int)(pixelsFromZero / mHourHeight); int minute = (int) (60 * (pixelsFromZero - hour * mHourHeight) / mHourHeight); - day.add(Calendar.HOUR, hour); - day.set(Calendar.MINUTE, minute); - return day; + sDay.add(Calendar.HOUR, hour); + sDay.set(Calendar.MINUTE, minute); + return sDay; } startPixel += mWidthPerDay + mColumnGap; } @@ -780,7 +787,7 @@ private Calendar getTimeFromPoint(float x, float y){ private void drawEvents(Calendar date, float startFromPixel, Canvas canvas) { if (mEventRects != null && mEventRects.size() > 0) { for (int i = 0; i < mEventRects.size(); i++) { - if (isSameDay(mEventRects.get(i).event.getStartTime(), date) && !mEventRects.get(i).event.isAllDay()){ + if (isSameDay(mEventRects.get(i).event.getStartTime(), date.getTimeInMillis()) && !mEventRects.get(i).event.isAllDay()){ // Calculate top. float top = mHourHeight * 24 * mEventRects.get(i).top / 1440 + mCurrentOrigin.y + mHeaderHeight + mHeaderRowPadding * 2 + mHeaderMarginBottom + mTimeTextHeight/2 + mEventMarginVertical; @@ -825,7 +832,7 @@ top < getHeight() && private void drawAllDayEvents(Calendar date, float startFromPixel, Canvas canvas) { if (mEventRects != null && mEventRects.size() > 0) { for (int i = 0; i < mEventRects.size(); i++) { - if (isSameDay(mEventRects.get(i).event.getStartTime(), date) && mEventRects.get(i).event.isAllDay()){ + if (isSameDay(mEventRects.get(i).event.getStartTime(), date.getTimeInMillis()) && mEventRects.get(i).event.isAllDay()){ // Calculate top. float top = mHeaderRowPadding * 2 + mHeaderMarginBottom + + mTimeTextHeight/2 + mEventMarginVertical; @@ -874,7 +881,7 @@ private void drawEventTitle(WeekViewEvent event, RectF rect, Canvas canvas, floa if (rect.bottom - rect.top - mEventPadding * 2 < 0) return; // Prepare the name of the event. - SpannableStringBuilder bob = new SpannableStringBuilder(); + SpannableStringBuilder bob = event.getStringBuilder(); if (event.getName() != null) { bob.append(event.getName()); bob.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0, bob.length(), 0); @@ -887,30 +894,43 @@ private void drawEventTitle(WeekViewEvent event, RectF rect, Canvas canvas, floa } int availableHeight = (int) (rect.bottom - originalTop - mEventPadding * 2); + boolean availableHeightRetained = availableHeight == event.getmAvailableHeight(); + if (!availableHeightRetained) { + event.setmAvailableHeight(availableHeight); + } int availableWidth = (int) (rect.right - originalLeft - mEventPadding * 2); + boolean availableWidthRetained = availableWidth == event.getmAvailableWidth(); + if (!availableWidthRetained) { + event.setmAvailableWidth(availableWidth); + } // Get text dimensions. - StaticLayout textLayout = new StaticLayout(bob, mEventTextPaint, availableWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + StaticLayout textLayout = availableWidthRetained ? event.getTextLayout() : + new StaticLayout(bob, mEventTextPaint, availableWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); int lineHeight = textLayout.getHeight() / textLayout.getLineCount(); if (availableHeight >= lineHeight) { - // Calculate available number of line counts. - int availableLineCount = availableHeight / lineHeight; - do { - // Ellipsize text to fit into event rect. - textLayout = new StaticLayout(TextUtils.ellipsize(bob, mEventTextPaint, availableLineCount * availableWidth, TextUtils.TruncateAt.END), mEventTextPaint, (int) (rect.right - originalLeft - mEventPadding * 2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - - // Reduce line count. - availableLineCount--; - - // Repeat until text is short enough. - } while (textLayout.getHeight() > availableHeight); - + if (!availableHeightRetained || !availableWidthRetained) { + // Calculate available number of line counts. + int availableLineCount = availableHeight / lineHeight; + do { + // Ellipsize text to fit into event rect. + textLayout = new StaticLayout( + TextUtils.ellipsize(bob, mEventTextPaint, availableLineCount * availableWidth, TextUtils.TruncateAt.END), + mEventTextPaint, (int) (rect.right - originalLeft - mEventPadding * 2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + + // Reduce line count. + availableLineCount--; + + // Repeat until text is short enough. + } while (textLayout.getHeight() > availableHeight); + event.setTextLayout(textLayout); + } // Draw text. canvas.save(); canvas.translate(originalLeft + mEventPadding, originalTop + mEventPadding); - textLayout.draw(canvas); + event.getTextLayout().draw(canvas); canvas.restore(); } } @@ -1051,7 +1071,7 @@ else if (periodToFetch == mFetchedPeriod+1){ * @param event The event to cache. */ private void cacheEvent(WeekViewEvent event) { - if(event.getStartTime().compareTo(event.getEndTime()) >= 0) + if(event.getStartTime() - event.getEndTime() >= 0) return; List splitedEvents = event.splitWeekViewEvents(); for(WeekViewEvent splitedEvent: splitedEvents){ @@ -1078,12 +1098,12 @@ private void sortEvents(List events) { Collections.sort(events, new Comparator() { @Override public int compare(WeekViewEvent event1, WeekViewEvent event2) { - long start1 = event1.getStartTime().getTimeInMillis(); - long start2 = event2.getStartTime().getTimeInMillis(); + long start1 = event1.getStartTime(); + long start2 = event2.getStartTime(); int comparator = start1 > start2 ? 1 : (start1 < start2 ? -1 : 0); if (comparator == 0) { - long end1 = event1.getEndTime().getTimeInMillis(); - long end2 = event2.getEndTime().getTimeInMillis(); + long end1 = event1.getEndTime(); + long end2 = event2.getEndTime(); comparator = end1 > end2 ? 1 : (end1 < end2 ? -1 : 0); } return comparator; @@ -1125,6 +1145,7 @@ private void computePositionOfEvents(List eventRects) { } } + private static final Calendar sEventTime = Calendar.getInstance(); /** * Expands all the events to maximum possible width. The events will try to occupy maximum * space available horizontally. @@ -1170,10 +1191,14 @@ else if (!isEventsCollide(eventRect.event, column.get(column.size()-1).event)) { eventRect.width = 1f / columns.size(); eventRect.left = j / columns.size(); if(!eventRect.event.isAllDay()) { - eventRect.top = eventRect.event.getStartTime().get(Calendar.HOUR_OF_DAY) * 60 + eventRect.event.getStartTime().get(Calendar.MINUTE); - eventRect.bottom = eventRect.event.getEndTime().get(Calendar.HOUR_OF_DAY) * 60 + eventRect.event.getEndTime().get(Calendar.MINUTE); - } - else{ + sEventTime.setTimeInMillis(eventRect.event.getStartTime()); + eventRect.top = sEventTime.get(Calendar.HOUR_OF_DAY) * 60 + + sEventTime.get(Calendar.MINUTE); + sEventTime.setTimeInMillis(eventRect.event.getEndTime()); + eventRect.bottom = sEventTime.get(Calendar.HOUR_OF_DAY) * 60 + + sEventTime.get(Calendar.MINUTE); + + } else { eventRect.top = 0; eventRect.bottom = mAllDayEventHeight; } @@ -1192,10 +1217,10 @@ else if (!isEventsCollide(eventRect.event, column.get(column.size()-1).event)) { * @return true if the events overlap. */ private boolean isEventsCollide(WeekViewEvent event1, WeekViewEvent event2) { - long start1 = event1.getStartTime().getTimeInMillis(); - long end1 = event1.getEndTime().getTimeInMillis(); - long start2 = event2.getStartTime().getTimeInMillis(); - long end2 = event2.getEndTime().getTimeInMillis(); + long start1 = event1.getStartTime(); + long end1 = event1.getEndTime(); + long start2 = event2.getStartTime(); + long end2 = event2.getEndTime(); return !((start1 >= end2) || (end1 <= start2)); } @@ -1310,15 +1335,16 @@ public String interpretDate(Calendar date) { } } + private final Calendar sCalendar = Calendar.getInstance(); @Override public String interpretTime(int hour) { - Calendar calendar = Calendar.getInstance(); - calendar.set(Calendar.HOUR_OF_DAY, hour); - calendar.set(Calendar.MINUTE, 0); + sCalendar.setTimeInMillis(System.currentTimeMillis()); + sCalendar.set(Calendar.HOUR_OF_DAY, hour); + sCalendar.set(Calendar.MINUTE, 0); try { SimpleDateFormat sdf = DateFormat.is24HourFormat(getContext()) ? new SimpleDateFormat("HH:mm", Locale.getDefault()) : new SimpleDateFormat("hh a", Locale.getDefault()); - return sdf.format(calendar.getTime()); + return sdf.format(sCalendar.getTime()); } catch (Exception e) { e.printStackTrace(); return ""; @@ -1906,12 +1932,14 @@ private boolean forceFinishScroll() { // ///////////////////////////////////////////////////////////////// + // use additional today Calendar to avoid modifying the calendar return by today() + private static final Calendar sOtherToday = Calendar.getInstance(); /** * Show today on the week view. */ public void goToToday() { - Calendar today = Calendar.getInstance(); - goToDate(today); + sOtherToday.setTimeInMillis(System.currentTimeMillis()); + goToDate(sOtherToday); } /** @@ -1934,15 +1962,15 @@ public void goToDate(Calendar date) { mRefreshEvents = true; - Calendar today = Calendar.getInstance(); - today.set(Calendar.HOUR_OF_DAY, 0); - today.set(Calendar.MINUTE, 0); - today.set(Calendar.SECOND, 0); - today.set(Calendar.MILLISECOND, 0); + sOtherToday.setTimeInMillis(System.currentTimeMillis()); + sOtherToday.set(Calendar.HOUR_OF_DAY, 0); + sOtherToday.set(Calendar.MINUTE, 0); + sOtherToday.set(Calendar.SECOND, 0); + sOtherToday.set(Calendar.MILLISECOND, 0); long day = 1000L * 60L * 60L * 24L; long dateInMillis = date.getTimeInMillis() + date.getTimeZone().getOffset(date.getTimeInMillis()); - long todayInMillis = today.getTimeInMillis() + today.getTimeZone().getOffset(today.getTimeInMillis()); + long todayInMillis = sOtherToday.getTimeInMillis() + sOtherToday.getTimeZone().getOffset(sOtherToday.getTimeInMillis()); long dateDifference = (dateInMillis/day) - (todayInMillis/day); mCurrentOrigin.x = - dateDifference * (mWidthPerDay + mColumnGap); invalidate(); diff --git a/library/src/main/java/com/alamkanak/weekview/WeekViewEvent.java b/library/src/main/java/com/alamkanak/weekview/WeekViewEvent.java index f49ab5703..888e62621 100644 --- a/library/src/main/java/com/alamkanak/weekview/WeekViewEvent.java +++ b/library/src/main/java/com/alamkanak/weekview/WeekViewEvent.java @@ -1,5 +1,9 @@ package com.alamkanak.weekview; +import android.graphics.Typeface; +import android.text.SpannableStringBuilder; +import android.text.StaticLayout; +import android.text.style.StyleSpan; import java.util.ArrayList; import java.util.Calendar; import java.util.List; @@ -11,12 +15,21 @@ * Website: http://april-shower.com */ public class WeekViewEvent { + + private static final Calendar sStartCalendar = Calendar.getInstance(); + private static final Calendar sEndCalendar = Calendar.getInstance(); + private long mId; - private Calendar mStartTime; - private Calendar mEndTime; + private long mStartTime; + private long mEndTime; private String mName; private String mLocation; private int mColor; + private int mAvailableHeight; + private int mAvailableWidth; + private StaticLayout mTextLayout; + private SpannableStringBuilder mStringBuilder = new SpannableStringBuilder(); + private boolean mAllDay; public WeekViewEvent(){ @@ -41,19 +54,21 @@ public WeekViewEvent(){ public WeekViewEvent(long id, String name, int startYear, int startMonth, int startDay, int startHour, int startMinute, int endYear, int endMonth, int endDay, int endHour, int endMinute) { this.mId = id; - this.mStartTime = Calendar.getInstance(); - this.mStartTime.set(Calendar.YEAR, startYear); - this.mStartTime.set(Calendar.MONTH, startMonth-1); - this.mStartTime.set(Calendar.DAY_OF_MONTH, startDay); - this.mStartTime.set(Calendar.HOUR_OF_DAY, startHour); - this.mStartTime.set(Calendar.MINUTE, startMinute); + sStartCalendar.set(Calendar.YEAR, startYear); + sStartCalendar.set(Calendar.MONTH, startMonth-1); + sStartCalendar.set(Calendar.DAY_OF_MONTH, startDay); + sStartCalendar.set(Calendar.HOUR_OF_DAY, startHour); + sStartCalendar.set(Calendar.MINUTE, startMinute); - this.mEndTime = Calendar.getInstance(); - this.mEndTime.set(Calendar.YEAR, endYear); - this.mEndTime.set(Calendar.MONTH, endMonth-1); - this.mEndTime.set(Calendar.DAY_OF_MONTH, endDay); - this.mEndTime.set(Calendar.HOUR_OF_DAY, endHour); - this.mEndTime.set(Calendar.MINUTE, endMinute); + mStartTime = sStartCalendar.getTimeInMillis(); + + sEndCalendar.set(Calendar.YEAR, endYear); + sEndCalendar.set(Calendar.MONTH, endMonth-1); + sEndCalendar.set(Calendar.DAY_OF_MONTH, endDay); + sEndCalendar.set(Calendar.HOUR_OF_DAY, endHour); + sEndCalendar.set(Calendar.MINUTE, endMinute); + + mEndTime = sEndCalendar.getTimeInMillis(); this.mName = name; } @@ -68,6 +83,24 @@ public WeekViewEvent(long id, String name, int startYear, int startMonth, int st * @param allDay Is the event an all day event. */ public WeekViewEvent(long id, String name, String location, Calendar startTime, Calendar endTime, boolean allDay) { + this.mId = id; + this.mName = name; + this.mLocation = location; + this.mStartTime = startTime.getTimeInMillis(); + this.mEndTime = endTime.getTimeInMillis(); + this.mAllDay = allDay; + } + + /** + * Initializes the event for week view. + * @param id The id of the event. + * @param name Name of the event. + * @param location The location of the event. + * @param startTime The time when the event starts. + * @param endTime The time when the event ends. + * @param allDay Is the event an all day event. + */ + public WeekViewEvent(long id, String name, String location, long startTime, long endTime, boolean allDay) { this.mId = id; this.mName = name; this.mLocation = location; @@ -76,6 +109,7 @@ public WeekViewEvent(long id, String name, String location, Calendar startTime, this.mAllDay = allDay; } + /** * Initializes the event for week view. * @param id The id of the event. @@ -100,20 +134,28 @@ public WeekViewEvent(long id, String name, Calendar startTime, Calendar endTime) } - public Calendar getStartTime() { + public long getStartTime() { return mStartTime; } public void setStartTime(Calendar startTime) { - this.mStartTime = startTime; + this.mStartTime = startTime.getTimeInMillis(); + } + + public void setStartTime(long startTime) { + mStartTime = startTime; } - public Calendar getEndTime() { + public long getEndTime() { return mEndTime; } public void setEndTime(Calendar endTime) { - this.mEndTime = endTime; + this.mEndTime = endTime.getTimeInMillis(); + } + + public void setEndTime(long endTime) { + mEndTime = endTime; } public String getName() { @@ -122,6 +164,7 @@ public String getName() { public void setName(String name) { this.mName = name; + refreshStringBuilder(); } public String getLocation() { @@ -130,6 +173,8 @@ public String getLocation() { public void setLocation(String location) { this.mLocation = location; + // Prepare the location of the event. + refreshStringBuilder(); } public int getColor() { @@ -156,6 +201,35 @@ public void setId(long id) { this.mId = id; } + public int getmAvailableHeight() { + return mAvailableHeight; + } + + public void setmAvailableHeight(int mAvailableHeight) { + this.mAvailableHeight = mAvailableHeight; + } + + public int getmAvailableWidth() { + return mAvailableWidth; + } + + public void setmAvailableWidth(int mAvailableWidth) { + this.mAvailableWidth = mAvailableWidth; + } + + public StaticLayout getTextLayout() { + return mTextLayout; + } + + public void setTextLayout(StaticLayout mTextLayout) { + this.mTextLayout = mTextLayout; + } + + public SpannableStringBuilder getStringBuilder() { + return mStringBuilder; + } + + @Override public boolean equals(Object o) { if (this == o) return true; @@ -172,50 +246,63 @@ public int hashCode() { return (int) (mId ^ (mId >>> 32)); } + private static Calendar sEndTimeCalendar = Calendar.getInstance(); + private static Calendar sOverDayCalendar = Calendar.getInstance(); public List splitWeekViewEvents(){ //This function splits the WeekViewEvent in WeekViewEvents by day List events = new ArrayList(); // The first millisecond of the next day is still the same day. (no need to split events for this). - Calendar endTime = (Calendar) this.getEndTime().clone(); - endTime.add(Calendar.MILLISECOND, -1); - if (!isSameDay(this.getStartTime(), endTime)) { - endTime = (Calendar) this.getStartTime().clone(); - endTime.set(Calendar.HOUR_OF_DAY, 23); - endTime.set(Calendar.MINUTE, 59); - WeekViewEvent event1 = new WeekViewEvent(this.getId(), this.getName(), this.getLocation(), this.getStartTime(), endTime, this.isAllDay()); + if (!isSameDay(mStartTime, mEndTime - 1)) { + sEndTimeCalendar.setTimeInMillis(mStartTime); + sEndTimeCalendar.set(Calendar.HOUR_OF_DAY, 23); + sEndTimeCalendar.set(Calendar.MINUTE, 59); + WeekViewEvent event1 = new WeekViewEvent(this.getId(), this.getName(), this.getLocation(), this.getStartTime(), sEndCalendar.getTimeInMillis(), this.isAllDay()); event1.setColor(this.getColor()); events.add(event1); // Add other days. - Calendar otherDay = (Calendar) this.getStartTime().clone(); - otherDay.add(Calendar.DATE, 1); - while (!isSameDay(otherDay, this.getEndTime())) { - Calendar overDay = (Calendar) otherDay.clone(); - overDay.set(Calendar.HOUR_OF_DAY, 0); - overDay.set(Calendar.MINUTE, 0); - Calendar endOfOverDay = (Calendar) overDay.clone(); - endOfOverDay.set(Calendar.HOUR_OF_DAY, 23); - endOfOverDay.set(Calendar.MINUTE, 59); - WeekViewEvent eventMore = new WeekViewEvent(this.getId(), this.getName(), null, overDay, endOfOverDay, this.isAllDay()); - eventMore.setColor(this.getColor()); + sEndTimeCalendar.add(Calendar.DATE, 1); + while (!isSameDay(sEndTimeCalendar.getTimeInMillis(), mEndTime)) { + sOverDayCalendar.setTimeInMillis(sEndTimeCalendar.getTimeInMillis()); + sOverDayCalendar.set(Calendar.HOUR_OF_DAY, 0); + sOverDayCalendar.set(Calendar.MINUTE, 0); + long startOfOverDay = sOverDayCalendar.getTimeInMillis(); + sOverDayCalendar.set(Calendar.HOUR_OF_DAY, 23); + sOverDayCalendar.set(Calendar.MINUTE, 59); + long endOfOverDay = sOverDayCalendar.getTimeInMillis(); + WeekViewEvent eventMore = new WeekViewEvent(mId, mName, null, + startOfOverDay, endOfOverDay, mAllDay); + eventMore.setColor(mColor); events.add(eventMore); // Add next day. - otherDay.add(Calendar.DATE, 1); + sEndTimeCalendar.add(Calendar.DATE, 1); } // Add last day. - Calendar startTime = (Calendar) this.getEndTime().clone(); - startTime.set(Calendar.HOUR_OF_DAY, 0); - startTime.set(Calendar.MINUTE, 0); - WeekViewEvent event2 = new WeekViewEvent(this.getId(), this.getName(), this.getLocation(), startTime, this.getEndTime(), this.isAllDay()); - event2.setColor(this.getColor()); + sEndTimeCalendar.setTimeInMillis(mEndTime); + sEndTimeCalendar.set(Calendar.HOUR_OF_DAY, 0); + sEndTimeCalendar.set(Calendar.MINUTE, 0); + WeekViewEvent event2 = new WeekViewEvent(mId, mName, mLocation, + sEndTimeCalendar.getTimeInMillis(), mEndTime, mAllDay); + event2.setColor(mColor); events.add(event2); - } - else{ + } else { events.add(this); } return events; } + + private void refreshStringBuilder() { + mStringBuilder.clear(); + if (mName != null) { + mStringBuilder.append(mName); + mStringBuilder.setSpan(new StyleSpan(Typeface.BOLD), 0, mStringBuilder.length(), 0); + mStringBuilder.append(' '); + } + if (mLocation != null) { + mStringBuilder.append(mLocation); + } + } } diff --git a/library/src/main/java/com/alamkanak/weekview/WeekViewUtil.java b/library/src/main/java/com/alamkanak/weekview/WeekViewUtil.java index 24264669d..8b37394f1 100644 --- a/library/src/main/java/com/alamkanak/weekview/WeekViewUtil.java +++ b/library/src/main/java/com/alamkanak/weekview/WeekViewUtil.java @@ -24,16 +24,26 @@ public static boolean isSameDay(Calendar dayOne, Calendar dayTwo) { return dayOne.get(Calendar.YEAR) == dayTwo.get(Calendar.YEAR) && dayOne.get(Calendar.DAY_OF_YEAR) == dayTwo.get(Calendar.DAY_OF_YEAR); } + private static Calendar sDayOne = Calendar.getInstance(); + private static Calendar sDayTwo = Calendar.getInstance(); + public static boolean isSameDay(long dayOne, long dayTwo) { + sDayOne.setTimeInMillis(dayOne); + sDayTwo.setTimeInMillis(dayTwo); + return isSameDay(sDayOne, sDayTwo); + } + + + private static final Calendar sToday = Calendar.getInstance(); /** * Returns a calendar instance at the start of this day * @return the calendar instance */ public static Calendar today(){ - Calendar today = Calendar.getInstance(); - today.set(Calendar.HOUR_OF_DAY, 0); - today.set(Calendar.MINUTE, 0); - today.set(Calendar.SECOND, 0); - today.set(Calendar.MILLISECOND, 0); - return today; + sToday.setTimeInMillis(System.currentTimeMillis()); + sToday.set(Calendar.HOUR_OF_DAY, 0); + sToday.set(Calendar.MINUTE, 0); + sToday.set(Calendar.SECOND, 0); + sToday.set(Calendar.MILLISECOND, 0); + return sToday; } } diff --git a/sample/src/main/java/com/alamkanak/weekview/sample/AsynchronousActivity.java b/sample/src/main/java/com/alamkanak/weekview/sample/AsynchronousActivity.java index 6feda05f9..af02c24ea 100644 --- a/sample/src/main/java/com/alamkanak/weekview/sample/AsynchronousActivity.java +++ b/sample/src/main/java/com/alamkanak/weekview/sample/AsynchronousActivity.java @@ -49,6 +49,9 @@ public List onMonthChange(int newYear, int newMonth) { return matchedEvents; } + + private static final Calendar sStartTime = Calendar.getInstance(); + private static final Calendar sEndTime = Calendar.getInstance(); /** * Checks if an event falls into a specific year and month. * @param event The event to check for. @@ -57,7 +60,10 @@ public List onMonthChange(int newYear, int newMonth) { * @return True if the event matches the year and month. */ private boolean eventMatches(WeekViewEvent event, int year, int month) { - return (event.getStartTime().get(Calendar.YEAR) == year && event.getStartTime().get(Calendar.MONTH) == month - 1) || (event.getEndTime().get(Calendar.YEAR) == year && event.getEndTime().get(Calendar.MONTH) == month - 1); + sStartTime.setTimeInMillis(event.getStartTime()); + sEndTime.setTimeInMillis(event.getEndTime()); + return (sStartTime.get(Calendar.YEAR) == year && sStartTime.get(Calendar.MONTH) == month - 1) + || (sEndTime.get(Calendar.YEAR) == year && sEndTime.get(Calendar.MONTH) == month - 1); } @Override From ced9a641e95d89d7fc2a4c900106a81f9c9a763d Mon Sep 17 00:00:00 2001 From: Kitman Lai Date: Fri, 7 Jul 2017 14:50:54 +0800 Subject: [PATCH 3/3] Update README.md --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index de96370a8..ed0a7009d 100644 --- a/README.md +++ b/README.md @@ -228,10 +228,15 @@ Changelog * Added support for overlapping events +**Lai Kitman Fork** + +* remove almost all calendar instance to avoid memory leak +* optimize performance on large amount of events + License ---------- - Copyright 2014 Raquib-ul-Alam +    Copyright 2017 Lai Kitman Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.