diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCard.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCard.java index 135dc0a23..6d9f4bda1 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCard.java +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCard.java @@ -54,9 +54,6 @@ public class BarCard extends HabitCard @BindView(R.id.title) TextView title; - @Nullable - private TaskRunner taskRunner; - private int bucketSize; public BarCard(Context context) @@ -85,29 +82,13 @@ public class BarCard extends HabitCard refreshData(); } - @Override - protected void refreshData() - { - if (taskRunner == null) return; - taskRunner.execute(new RefreshTask(getHabit())); - } - private void init() { inflate(getContext(), R.layout.show_habit_bar, this); ButterKnife.bind(this); - boolSpinner.setSelection(1); numericalSpinner.setSelection(2); bucketSize = 7; - - Context appContext = getContext().getApplicationContext(); - if (appContext instanceof HabitsApplication) - { - HabitsApplication app = (HabitsApplication) appContext; - taskRunner = app.getComponent().getTaskRunner(); - } - if (isInEditMode()) initEditMode(); } @@ -119,11 +100,17 @@ public class BarCard extends HabitCard chart.populateWithRandomData(); } - private class RefreshTask implements Task + @Override + protected Task createRefreshTask() + { + return new RefreshTask(getHabit()); + } + + private class RefreshTask extends CancelableTask { private final Habit habit; - public RefreshTask(Habit habit) + RefreshTask(Habit habit) { this.habit = habit; } @@ -131,6 +118,7 @@ public class BarCard extends HabitCard @Override public void doInBackground() { + if (isCanceled()) return; List checkmarks; if (bucketSize == 1) checkmarks = habit.getCheckmarks().getAll(); else checkmarks = habit.getCheckmarks().groupBy(getTruncateField(bucketSize)); diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCard.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCard.java index ff24596c3..f5df21b78 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCard.java +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCard.java @@ -43,9 +43,6 @@ public class FrequencyCard extends HabitCard @BindView(R.id.frequencyChart) FrequencyChart chart; - @Nullable - private TaskRunner taskRunner; - public FrequencyCard(Context context) { super(context); @@ -59,24 +56,15 @@ public class FrequencyCard extends HabitCard } @Override - protected void refreshData() + protected Task createRefreshTask() { - if(taskRunner == null) return; - taskRunner.execute(new RefreshTask()); + return new RefreshTask(); } private void init() { inflate(getContext(), R.layout.show_habit_frequency, this); ButterKnife.bind(this); - - Context appContext = getContext().getApplicationContext(); - if(appContext instanceof HabitsApplication) - { - HabitsApplication app = (HabitsApplication) appContext; - taskRunner = app.getComponent().getTaskRunner(); - } - if (isInEditMode()) initEditMode(); } @@ -88,11 +76,12 @@ public class FrequencyCard extends HabitCard chart.populateWithRandomData(); } - private class RefreshTask implements Task + private class RefreshTask extends CancelableTask { @Override public void doInBackground() { + if (isCanceled()) return; RepetitionList reps = getHabit().getRepetitions(); HashMap frequency = reps.getWeekdayFrequency(); chart.setFrequency(frequency); diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HabitCard.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HabitCard.java index 255b518e1..f00754dd0 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HabitCard.java +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HabitCard.java @@ -24,8 +24,10 @@ import android.support.annotation.*; import android.util.*; import android.widget.*; +import org.isoron.uhabits.*; import org.isoron.uhabits.core.models.*; import org.isoron.uhabits.core.models.memory.*; +import org.isoron.uhabits.core.tasks.*; public abstract class HabitCard extends LinearLayout implements ModelObservable.Listener @@ -33,6 +35,12 @@ public abstract class HabitCard extends LinearLayout @NonNull private Habit habit; + @Nullable + private TaskRunner taskRunner; + + @Nullable + private Task currentRefreshTask; + public HabitCard(Context context) { super(context); @@ -82,7 +90,15 @@ public abstract class HabitCard extends LinearLayout super.onDetachedFromWindow(); } - protected abstract void refreshData(); + protected void refreshData() + { + if(taskRunner == null) return; + if(currentRefreshTask != null) currentRefreshTask.cancel(); + currentRefreshTask = createRefreshTask(); + taskRunner.execute(currentRefreshTask); + } + + protected abstract Task createRefreshTask(); private void attachTo(Habit habit) { @@ -99,5 +115,11 @@ public abstract class HabitCard extends LinearLayout private void init() { if(!isInEditMode()) habit = new MemoryModelFactory().buildHabit(); + Context appContext = getContext().getApplicationContext(); + if(appContext instanceof HabitsApplication) + { + HabitsApplication app = (HabitsApplication) appContext; + taskRunner = app.getComponent().getTaskRunner(); + } } } diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCard.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCard.java index e59aecf73..f76c50304 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCard.java +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCard.java @@ -44,9 +44,6 @@ public class HistoryCard extends HabitCard @NonNull private Controller controller; - @Nullable - private TaskRunner taskRunner; - public HistoryCard(Context context) { super(context); @@ -70,25 +67,10 @@ public class HistoryCard extends HabitCard this.controller = controller; } - @Override - protected void refreshData() - { - if(taskRunner == null) return; - taskRunner.execute(new RefreshTask(getHabit())); - } - private void init() { inflate(getContext(), R.layout.show_habit_history, this); ButterKnife.bind(this); - - Context appContext = getContext().getApplicationContext(); - if (appContext instanceof HabitsApplication) - { - HabitsApplication app = (HabitsApplication) appContext; - taskRunner = app.getComponent().getTaskRunner(); - } - controller = new Controller() {}; if (isInEditMode()) initEditMode(); } @@ -101,20 +83,30 @@ public class HistoryCard extends HabitCard chart.populateWithRandomData(); } + @Override + protected Task createRefreshTask() + { + return new RefreshTask(getHabit()); + } + public interface Controller { default void onEditHistoryButtonClick() {} } - private class RefreshTask implements Task + private class RefreshTask extends CancelableTask { private final Habit habit; - public RefreshTask(Habit habit) {this.habit = habit;} + private RefreshTask(Habit habit) + { + this.habit = habit; + } @Override public void doInBackground() { + if (isCanceled()) return; int checkmarks[] = habit.getCheckmarks().getAllValues(); chart.setCheckmarks(checkmarks); } diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/OverviewCard.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/OverviewCard.java index f1acb1cdd..1637ffb5e 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/OverviewCard.java +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/OverviewCard.java @@ -60,9 +60,6 @@ public class OverviewCard extends HabitCard private int color; - @Nullable - private TaskRunner taskRunner; - public OverviewCard(Context context) { super(context); @@ -75,13 +72,6 @@ public class OverviewCard extends HabitCard init(); } - @Override - protected void refreshData() - { - if(taskRunner == null) return; - taskRunner.execute(new RefreshTask()); - } - private String formatPercentageDiff(float percentageDiff) { return String.format("%s%.0f%%", (percentageDiff >= 0 ? "+" : "\u2212"), @@ -90,17 +80,9 @@ public class OverviewCard extends HabitCard private void init() { - Context appContext = getContext().getApplicationContext(); - if (appContext instanceof HabitsApplication) - { - HabitsApplication app = (HabitsApplication) appContext; - taskRunner = app.getComponent().getTaskRunner(); - } - inflate(getContext(), R.layout.show_habit_overview, this); ButterKnife.bind(this); cache = new Cache(); - if (isInEditMode()) initEditMode(); } @@ -146,20 +128,27 @@ public class OverviewCard extends HabitCard private class Cache { - public float todayScore; + float todayScore; + + float lastMonthScore; - public float lastMonthScore; + float lastYearScore; - public float lastYearScore; + long totalCount; + } - public long totalCount; + @Override + protected Task createRefreshTask() + { + return new RefreshTask(); } - private class RefreshTask implements Task + private class RefreshTask extends CancelableTask { @Override public void doInBackground() { + if (isCanceled()) return; Habit habit = getHabit(); ScoreList scores = habit.getScores(); @@ -177,6 +166,7 @@ public class OverviewCard extends HabitCard @Override public void onPostExecute() { + if (isCanceled()) return; refreshScore(); } diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/ScoreCard.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/ScoreCard.java index eb81a954e..bb0d01964 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/ScoreCard.java +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/ScoreCard.java @@ -52,9 +52,6 @@ public class ScoreCard extends HabitCard private int bucketSize; - @Nullable - private TaskRunner taskRunner; - @Nullable private Preferences prefs; @@ -94,13 +91,6 @@ public class ScoreCard extends HabitCard refreshData(); } - @Override - protected void refreshData() - { - if(taskRunner == null) return; - taskRunner.execute(new RefreshTask()); - } - private int getDefaultSpinnerPosition() { if(prefs == null) return 0; @@ -113,7 +103,6 @@ public class ScoreCard extends HabitCard if (appContext instanceof HabitsApplication) { HabitsApplication app = (HabitsApplication) appContext; - taskRunner = app.getComponent().getTaskRunner(); prefs = app.getComponent().getPreferences(); } @@ -140,11 +129,18 @@ public class ScoreCard extends HabitCard bucketSize = BUCKET_SIZES[position]; } - private class RefreshTask implements Task + @Override + protected Task createRefreshTask() + { + return new RefreshTask(); + } + + private class RefreshTask extends CancelableTask { @Override public void doInBackground() { + if (isCanceled()) return; List scores; ScoreList scoreList = getHabit().getScores(); diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/StreakCard.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/StreakCard.java index e4f07e6d5..4f3d6f5f6 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/StreakCard.java +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/StreakCard.java @@ -45,9 +45,6 @@ public class StreakCard extends HabitCard @BindView(R.id.streakChart) StreakChart streakChart; - @Nullable - private TaskRunner taskRunner; - public StreakCard(Context context) { super(context); @@ -60,22 +57,8 @@ public class StreakCard extends HabitCard init(); } - @Override - protected void refreshData() - { - if(taskRunner == null) return; - taskRunner.execute(new RefreshTask()); - } - private void init() { - Context appContext = getContext().getApplicationContext(); - if (appContext instanceof HabitsApplication) - { - HabitsApplication app = (HabitsApplication) appContext; - taskRunner = app.getComponent().getTaskRunner(); - } - inflate(getContext(), R.layout.show_habit_streak, this); ButterKnife.bind(this); setOrientation(VERTICAL); @@ -90,13 +73,20 @@ public class StreakCard extends HabitCard streakChart.populateWithRandomData(); } - private class RefreshTask implements Task + @Override + protected Task createRefreshTask() + { + return new RefreshTask(); + } + + private class RefreshTask extends CancelableTask { - public List bestStreaks; + List bestStreaks; @Override public void doInBackground() { + if (isCanceled()) return; StreakList streaks = getHabit().getStreaks(); bestStreaks = streaks.getBest(NUM_STREAKS); } @@ -104,6 +94,7 @@ public class StreakCard extends HabitCard @Override public void onPostExecute() { + if (isCanceled()) return; streakChart.setStreaks(bestStreaks); } diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCard.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCard.java index 74e6b131d..ac8605862 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCard.java +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCard.java @@ -27,6 +27,7 @@ import android.widget.*; import org.isoron.uhabits.R; import org.isoron.uhabits.core.models.*; +import org.isoron.uhabits.core.tasks.*; import org.isoron.uhabits.utils.*; import butterknife.*; @@ -111,4 +112,10 @@ public class SubtitleCard extends HabitCard AndroidDateUtils.formatTime(getContext(), reminder.getHour(), reminder.getMinute())); } + + @Override + protected Task createRefreshTask() { + // Never called + throw new IllegalStateException(); + } } diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/tasks/AndroidTaskRunner.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/tasks/AndroidTaskRunner.java index 7b60834ba..17df191c7 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/tasks/AndroidTaskRunner.java +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/tasks/AndroidTaskRunner.java @@ -87,6 +87,7 @@ public class AndroidTaskRunner implements TaskRunner private class CustomAsyncTask extends AsyncTask { private final Task task; + private boolean isCancelled = false; public CustomAsyncTask(Task task) { @@ -106,6 +107,7 @@ public class AndroidTaskRunner implements TaskRunner @Override protected Void doInBackground(Void... params) { + if(isCancelled) return null; task.doInBackground(); return null; } @@ -113,6 +115,7 @@ public class AndroidTaskRunner implements TaskRunner @Override protected void onPostExecute(Void aVoid) { + if(isCancelled) return; task.onPostExecute(); activeTasks.remove(this); taskToAsyncTask.remove(task); @@ -122,6 +125,8 @@ public class AndroidTaskRunner implements TaskRunner @Override protected void onPreExecute() { + isCancelled = task.isCanceled(); + if(isCancelled) return; for (Listener l : listeners) l.onTaskStarted(task); activeTasks.add(this); taskToAsyncTask.put(task, this); diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/tasks/CancelableTask.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/tasks/CancelableTask.java new file mode 100644 index 000000000..9b4557b32 --- /dev/null +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/tasks/CancelableTask.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2016 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +package org.isoron.uhabits.core.tasks; + +public abstract class CancelableTask implements Task +{ + private boolean isCanceled = false; + + @Override + public synchronized void cancel() + { + isCanceled = true; + } + + @Override + public synchronized boolean isCanceled() + { + return isCanceled; + } +} diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/tasks/SingleThreadTaskRunner.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/tasks/SingleThreadTaskRunner.java index f01257839..5bd2e09f5 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/tasks/SingleThreadTaskRunner.java +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/tasks/SingleThreadTaskRunner.java @@ -35,10 +35,13 @@ public class SingleThreadTaskRunner implements TaskRunner public void execute(Task task) { for(Listener l : listeners) l.onTaskStarted(task); - task.onAttached(this); - task.onPreExecute(); - task.doInBackground(); - task.onPostExecute(); + if(!task.isCanceled()) + { + task.onAttached(this); + task.onPreExecute(); + task.doInBackground(); + task.onPostExecute(); + } for(Listener l : listeners) l.onTaskFinished(task); } diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/tasks/Task.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/tasks/Task.java index 3531a6314..cff7434c8 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/tasks/Task.java +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/tasks/Task.java @@ -25,6 +25,11 @@ public interface Task { default void cancel() {} + default boolean isCanceled() + { + return false; + } + void doInBackground(); default void onAttached(@NonNull TaskRunner runner) {}