mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
Dashboard: Use database read lock, enable parallel async tasks
This commit is contained in:
+56
-80
@@ -83,6 +83,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardVO2Max
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardVO2MaxRunningWidget;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.CachedValue;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DashboardUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
@@ -382,118 +383,93 @@ public class DashboardFragment extends Fragment implements MenuProvider {
|
||||
public int timeFrom;
|
||||
public int timeTo;
|
||||
public final List<GeneralizedActivity> generalizedActivities = Collections.synchronizedList(new ArrayList<>());
|
||||
private int stepsTotal;
|
||||
private float stepsGoalFactor;
|
||||
private int restingCaloriesTotal;
|
||||
private int activeCaloriesTotal;
|
||||
private float activeCaloriesGoalFactor;
|
||||
private int caloriesTotal;
|
||||
private long sleepTotalMinutes;
|
||||
private float sleepGoalFactor;
|
||||
private float distanceTotalMeters;
|
||||
private float distanceGoalFactor;
|
||||
private long activeMinutesTotal;
|
||||
private float activeMinutesGoalFactor;
|
||||
private final CachedValue<Integer> stepsTotal = new CachedValue<>();
|
||||
private final CachedValue<Float> stepsGoalFactor = new CachedValue<>();
|
||||
private final CachedValue<Integer> restingCaloriesTotal = new CachedValue<>();
|
||||
private final CachedValue<Integer> activeCaloriesTotal = new CachedValue<>();
|
||||
private final CachedValue<Float> activeCaloriesGoalFactor = new CachedValue<>();
|
||||
private final CachedValue<Long> sleepTotalMinutes = new CachedValue<>();
|
||||
private final CachedValue<Float> sleepGoalFactor = new CachedValue<>();
|
||||
private final CachedValue<Float> distanceTotalMeters = new CachedValue<>();
|
||||
private final CachedValue<Float> distanceGoalFactor = new CachedValue<>();
|
||||
private final CachedValue<Long> activeMinutesTotal = new CachedValue<>();
|
||||
private final CachedValue<Float> activeMinutesGoalFactor = new CachedValue<>();
|
||||
private final Map<String, Serializable> genericData = new ConcurrentHashMap<>();
|
||||
|
||||
public void clear() {
|
||||
restingCaloriesTotal = 0;
|
||||
activeCaloriesTotal = 0;
|
||||
activeCaloriesGoalFactor = 0;
|
||||
caloriesTotal = 0;
|
||||
stepsTotal = 0;
|
||||
stepsGoalFactor = 0;
|
||||
sleepTotalMinutes = 0;
|
||||
sleepGoalFactor = 0;
|
||||
distanceTotalMeters = 0;
|
||||
distanceGoalFactor = 0;
|
||||
activeMinutesTotal = 0;
|
||||
activeMinutesGoalFactor = 0;
|
||||
restingCaloriesTotal.clear();
|
||||
activeCaloriesTotal.clear();
|
||||
activeCaloriesGoalFactor.clear();
|
||||
stepsTotal.clear();
|
||||
stepsGoalFactor.clear();
|
||||
sleepTotalMinutes.clear();
|
||||
sleepGoalFactor.clear();
|
||||
distanceTotalMeters.clear();
|
||||
distanceGoalFactor.clear();
|
||||
activeMinutesTotal.clear();
|
||||
activeMinutesGoalFactor.clear();
|
||||
generalizedActivities.clear();
|
||||
genericData.clear();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return (stepsTotal == 0 &&
|
||||
stepsGoalFactor == 0 &&
|
||||
restingCaloriesTotal == 0 &&
|
||||
activeCaloriesTotal == 0 &&
|
||||
activeCaloriesGoalFactor == 0 &&
|
||||
caloriesTotal == 0 &&
|
||||
sleepTotalMinutes == 0 &&
|
||||
sleepGoalFactor == 0 &&
|
||||
distanceTotalMeters == 0 &&
|
||||
distanceGoalFactor == 0 &&
|
||||
activeMinutesTotal == 0 &&
|
||||
activeMinutesGoalFactor == 0 &&
|
||||
return (stepsTotal.isEmpty() &&
|
||||
stepsGoalFactor.isEmpty() &&
|
||||
restingCaloriesTotal.isEmpty() &&
|
||||
activeCaloriesTotal.isEmpty() &&
|
||||
activeCaloriesGoalFactor.isEmpty() &&
|
||||
sleepTotalMinutes.isEmpty() &&
|
||||
sleepGoalFactor.isEmpty() &&
|
||||
distanceTotalMeters.isEmpty() &&
|
||||
distanceGoalFactor.isEmpty() &&
|
||||
activeMinutesTotal.isEmpty() &&
|
||||
activeMinutesGoalFactor.isEmpty() &&
|
||||
genericData.isEmpty() &&
|
||||
generalizedActivities.isEmpty());
|
||||
}
|
||||
|
||||
public synchronized int getStepsTotal() {
|
||||
if (stepsTotal == 0)
|
||||
stepsTotal = DashboardUtils.getStepsTotal(this);
|
||||
return stepsTotal;
|
||||
public int getStepsTotal() {
|
||||
return stepsTotal.get(() -> DashboardUtils.getStepsTotal(this));
|
||||
}
|
||||
|
||||
public synchronized float getStepsGoalFactor() {
|
||||
if (stepsGoalFactor == 0)
|
||||
stepsGoalFactor = DashboardUtils.getStepsGoalFactor(this);
|
||||
return stepsGoalFactor;
|
||||
public float getStepsGoalFactor() {
|
||||
return stepsGoalFactor.get(() -> DashboardUtils.getStepsGoalFactor(this));
|
||||
}
|
||||
|
||||
public synchronized float getDistanceTotal() {
|
||||
if (distanceTotalMeters == 0)
|
||||
distanceTotalMeters = DashboardUtils.getDistanceTotal(this);
|
||||
return distanceTotalMeters;
|
||||
public float getDistanceTotal() {
|
||||
return distanceTotalMeters.get(() -> DashboardUtils.getDistanceTotal(this));
|
||||
}
|
||||
|
||||
public synchronized float getDistanceGoalFactor() {
|
||||
if (distanceGoalFactor == 0)
|
||||
distanceGoalFactor = DashboardUtils.getDistanceGoalFactor(this);
|
||||
return distanceGoalFactor;
|
||||
public float getDistanceGoalFactor() {
|
||||
return distanceGoalFactor.get(() -> DashboardUtils.getDistanceGoalFactor(this));
|
||||
}
|
||||
|
||||
public synchronized long getActiveMinutesTotal() {
|
||||
if (activeMinutesTotal == 0)
|
||||
activeMinutesTotal = DashboardUtils.getActiveMinutesTotal(this);
|
||||
return activeMinutesTotal;
|
||||
public long getActiveMinutesTotal() {
|
||||
return activeMinutesTotal.get(() -> DashboardUtils.getActiveMinutesTotal(this));
|
||||
}
|
||||
|
||||
public synchronized float getActiveMinutesGoalFactor() {
|
||||
if (activeMinutesGoalFactor == 0)
|
||||
activeMinutesGoalFactor = DashboardUtils.getActiveMinutesGoalFactor(this);
|
||||
return activeMinutesGoalFactor;
|
||||
public float getActiveMinutesGoalFactor() {
|
||||
return activeMinutesGoalFactor.get(() -> DashboardUtils.getActiveMinutesGoalFactor(this));
|
||||
}
|
||||
|
||||
public synchronized long getSleepMinutesTotal() {
|
||||
if (sleepTotalMinutes == 0)
|
||||
sleepTotalMinutes = DashboardUtils.getSleepMinutesTotal(this);
|
||||
return sleepTotalMinutes;
|
||||
public long getSleepMinutesTotal() {
|
||||
return sleepTotalMinutes.get(() -> DashboardUtils.getSleepMinutesTotal(this));
|
||||
}
|
||||
|
||||
public synchronized float getSleepMinutesGoalFactor() {
|
||||
if (sleepGoalFactor == 0)
|
||||
sleepGoalFactor = DashboardUtils.getSleepMinutesGoalFactor(this);
|
||||
return sleepGoalFactor;
|
||||
public float getSleepMinutesGoalFactor() {
|
||||
return sleepGoalFactor.get(() -> DashboardUtils.getSleepMinutesGoalFactor(this));
|
||||
}
|
||||
|
||||
public synchronized int getActiveCaloriesTotal() {
|
||||
if (activeCaloriesTotal == 0)
|
||||
activeCaloriesTotal = DashboardUtils.getActiveCaloriesTotal(this);
|
||||
return activeCaloriesTotal;
|
||||
public int getActiveCaloriesTotal() {
|
||||
return activeCaloriesTotal.get(() -> DashboardUtils.getActiveCaloriesTotal(this));
|
||||
}
|
||||
|
||||
public synchronized int getRestingCaloriesTotal() {
|
||||
if (restingCaloriesTotal == 0)
|
||||
restingCaloriesTotal = DashboardUtils.getRestingCaloriesTotal(this);
|
||||
return restingCaloriesTotal;
|
||||
public int getRestingCaloriesTotal() {
|
||||
return restingCaloriesTotal.get(() -> DashboardUtils.getRestingCaloriesTotal(this));
|
||||
}
|
||||
|
||||
public synchronized float getActiveCaloriesGoalFactor() {
|
||||
if (activeCaloriesGoalFactor == 0)
|
||||
activeCaloriesGoalFactor = DashboardUtils.getActiveCaloriesGoalFactor(this);
|
||||
return activeCaloriesGoalFactor;
|
||||
public float getActiveCaloriesGoalFactor() {
|
||||
return activeCaloriesGoalFactor.get(() -> DashboardUtils.getActiveCaloriesGoalFactor(this));
|
||||
}
|
||||
|
||||
public void put(final String key, final Serializable value) {
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ public abstract class AbstractDashboardVO2MaxWidget extends AbstractGaugeWidget
|
||||
|
||||
// Latest vo2max sample.
|
||||
Vo2MaxSample sample = null;
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
try (DBHandler dbHandler = GBApplication.acquireDbReadOnly()) {
|
||||
for (GBDevice dev : devices) {
|
||||
final Vo2MaxSampleProvider sampleProvider = (Vo2MaxSampleProvider) dev.getDeviceCoordinator().getVo2MaxSampleProvider(dev, dbHandler.getDaoSession());
|
||||
final Vo2MaxSample latestSample = sampleProvider.getLatestSample(getVO2MaxType(), dashboardData.timeTo * 1000L);
|
||||
|
||||
+2
-1
@@ -82,9 +82,10 @@ public abstract class AbstractGaugeWidget extends AbstractDashboardWidget {
|
||||
@Override
|
||||
protected void fillData() {
|
||||
if (gaugeBar == null) return;
|
||||
LOG.trace("Starting fillData for {}", getClass().getSimpleName());
|
||||
gaugeBar.post(() -> {
|
||||
final FillDataAsyncTask myAsyncTask = new FillDataAsyncTask();
|
||||
myAsyncTask.execute();
|
||||
myAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -71,7 +71,7 @@ public class DashboardBodyEnergyWidget extends AbstractGaugeWidget {
|
||||
// Latest stress sample for today
|
||||
BodyEnergySample sample = null;
|
||||
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
try (DBHandler dbHandler = GBApplication.acquireDbReadOnly()) {
|
||||
for (GBDevice dev : devices) {
|
||||
final BodyEnergySample latestSample = dev.getDeviceCoordinator().getBodyEnergySampleProvider(dev, dbHandler.getDaoSession())
|
||||
.getLatestSample();
|
||||
@@ -90,7 +90,7 @@ public class DashboardBodyEnergyWidget extends AbstractGaugeWidget {
|
||||
}
|
||||
} else {
|
||||
// Gain / loss for the period
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
try (DBHandler dbHandler = GBApplication.acquireDbReadOnly()) {
|
||||
for (GBDevice dev : devices) {
|
||||
if ((dashboardData.showAllDevices || dashboardData.showDeviceList.contains(dev.getAddress())) && dev.getDeviceCoordinator().supportsBodyEnergy(dev)) {
|
||||
final List<? extends BodyEnergySample> samples = dev.getDeviceCoordinator()
|
||||
|
||||
+2
-1
@@ -108,11 +108,12 @@ public class DashboardGoalsWidget extends AbstractDashboardWidget {
|
||||
@Override
|
||||
protected void fillData() {
|
||||
if (goalsView == null) return;
|
||||
LOG.trace("Starting fillData for {}", getClass().getSimpleName());
|
||||
goalsView.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
FillDataAsyncTask myAsyncTask = new FillDataAsyncTask();
|
||||
myAsyncTask.execute();
|
||||
myAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ public class DashboardHrvWidget extends AbstractGaugeWidget {
|
||||
|
||||
HrvSummarySample latestSummary = null;
|
||||
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
try (DBHandler dbHandler = GBApplication.acquireDbReadOnly()) {
|
||||
for (GBDevice dev : devices) {
|
||||
final TimeSampleProvider<? extends HrvSummarySample> hrvSummarySampleProvider = dev.getDeviceCoordinator().getHrvSummarySampleProvider(dev, dbHandler.getDaoSession());
|
||||
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ public class DashboardSleepScoreWidget extends AbstractGaugeWidget {
|
||||
final SleepScoreData data = new SleepScoreData();
|
||||
|
||||
SleepScoreSample sample = null;
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
try (DBHandler dbHandler = GBApplication.acquireDbReadOnly()) {
|
||||
for (GBDevice dev : devices) {
|
||||
TimeSampleProvider<? extends SleepScoreSample> provider = dev.getDeviceCoordinator().getSleepScoreProvider(dev, dbHandler.getDaoSession());
|
||||
final SleepScoreSample latestSample = provider.getLatestSample(dashboardData.timeTo * 1000L);
|
||||
|
||||
+4
-2
@@ -387,6 +387,8 @@ public class DashboardTodayWidget extends AbstractDashboardWidget {
|
||||
protected void fillData() {
|
||||
if (todayView == null) return;
|
||||
|
||||
LOG.trace("Starting fillData for {}", getClass().getSimpleName());
|
||||
|
||||
Prefs prefs = GBApplication.getPrefs();
|
||||
if (prefs.getBoolean("dashboard_widget_today_show_yesterday", false)) {
|
||||
Calendar today = Calendar.getInstance();
|
||||
@@ -401,7 +403,7 @@ public class DashboardTodayWidget extends AbstractDashboardWidget {
|
||||
@Override
|
||||
public void run() {
|
||||
FillDataAsyncTask myAsyncTask = new FillDataAsyncTask();
|
||||
myAsyncTask.execute();
|
||||
myAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -547,7 +549,7 @@ public class DashboardTodayWidget extends AbstractDashboardWidget {
|
||||
List<ActivitySample> allActivitySamples = new ArrayList<>();
|
||||
List<ActivitySession> stepSessions = new ArrayList<>();
|
||||
List<BaseActivitySummary> activitySummaries = null;
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
try (DBHandler dbHandler = GBApplication.acquireDbReadOnly()) {
|
||||
final List<Long> deviceIds = new LinkedList<>();
|
||||
for (GBDevice dev : devices) {
|
||||
if ((dashboardData.showAllDevices || dashboardData.showDeviceList.contains(dev.getAddress())) && dev.getDeviceCoordinator().supportsActivityTracking(dev)) {
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ public class DashboardStressData implements Serializable {
|
||||
|
||||
final int[] totalTime = new int[StressDailyFragment.StressType.values().length];
|
||||
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
try (DBHandler dbHandler = GBApplication.acquireDbReadOnly()) {
|
||||
for (GBDevice dev : devices) {
|
||||
if ((dashboardData.showAllDevices || dashboardData.showDeviceList.contains(dev.getAddress())) && dev.getDeviceCoordinator().supportsStressMeasurement(dev)) {
|
||||
final List<? extends StressSample> samples = dev.getDeviceCoordinator()
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class CachedValue<V extends Serializable> implements Serializable {
|
||||
private volatile V value = null;
|
||||
|
||||
public synchronized V get(final Supplier<V> supplier) {
|
||||
if (value == null) {
|
||||
value = supplier.get();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public synchronized void clear() {
|
||||
value = null;
|
||||
}
|
||||
|
||||
public synchronized boolean hasValue() {
|
||||
return value != null;
|
||||
}
|
||||
|
||||
public synchronized boolean isEmpty() {
|
||||
return value == null;
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ public class DashboardUtils {
|
||||
public static int getStepsTotal(DashboardFragment.DashboardData dashboardData) {
|
||||
List<GBDevice> devices = GBApplication.app().getDeviceManager().getDevices();
|
||||
int totalSteps = 0;
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
try (DBHandler dbHandler = GBApplication.acquireDbReadOnly()) {
|
||||
for (GBDevice dev : devices) {
|
||||
if ((dashboardData.showAllDevices || dashboardData.showDeviceList.contains(dev.getAddress())) && dev.getDeviceCoordinator().supportsStepCounter(dev)) {
|
||||
totalSteps += (int) getDailyTotals(dev, dbHandler, dashboardData.timeTo).getSteps();
|
||||
@@ -67,7 +67,7 @@ public class DashboardUtils {
|
||||
public static int getActiveCaloriesTotal(DashboardFragment.DashboardData dashboardData) {
|
||||
List<GBDevice> devices = GBApplication.app().getDeviceManager().getDevices();
|
||||
int totalActiveCalories = 0;
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
try (DBHandler dbHandler = GBApplication.acquireDbReadOnly()) {
|
||||
for (GBDevice dev : devices) {
|
||||
if ((dashboardData.showAllDevices || dashboardData.showDeviceList.contains(dev.getAddress())) && dev.getDeviceCoordinator().supportsActiveCalories(dev)) {
|
||||
totalActiveCalories += (int) getDailyTotals(dev, dbHandler, dashboardData.timeTo).getActiveCalories();
|
||||
@@ -84,7 +84,7 @@ public class DashboardUtils {
|
||||
List<GBDevice> devices = GBApplication.app().getDeviceManager().getDevices();
|
||||
int totalRestingCalories = 0;
|
||||
int totalRestingCaloriesDevices = 0;
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
try (DBHandler dbHandler = GBApplication.acquireDbReadOnly()) {
|
||||
for (GBDevice dev : devices) {
|
||||
if ((dashboardData.showAllDevices || dashboardData.showDeviceList.contains(dev.getAddress())) && dev.getDeviceCoordinator().supportsActiveCalories(dev)) {
|
||||
final int restingCalories = (int) getDailyTotals(dev, dbHandler, dashboardData.timeTo).getRestingCalories();
|
||||
@@ -121,7 +121,7 @@ public class DashboardUtils {
|
||||
public static long getSleepMinutesTotal(DashboardFragment.DashboardData dashboardData) {
|
||||
List<GBDevice> devices = GBApplication.app().getDeviceManager().getDevices();
|
||||
long totalSleepMinutes = 0;
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
try (DBHandler dbHandler = GBApplication.acquireDbReadOnly()) {
|
||||
for (GBDevice dev : devices) {
|
||||
if ((dashboardData.showAllDevices || dashboardData.showDeviceList.contains(dev.getAddress())) && dev.getDeviceCoordinator().supportsSleepMeasurement(dev)) {
|
||||
totalSleepMinutes += getSleep(dev, dbHandler, dashboardData.timeTo);
|
||||
@@ -145,10 +145,9 @@ public class DashboardUtils {
|
||||
public static float getDistanceTotal(DashboardFragment.DashboardData dashboardData) {
|
||||
ActivityUser activityUser = new ActivityUser();
|
||||
int stepLength = activityUser.getStepLengthCm();
|
||||
|
||||
List<GBDevice> devices = GBApplication.app().getDeviceManager().getDevices();
|
||||
long totalDistanceCm = 0;
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
try (DBHandler dbHandler = GBApplication.acquireDbReadOnly()) {
|
||||
for (GBDevice dev : devices) {
|
||||
if ((dashboardData.showAllDevices || dashboardData.showDeviceList.contains(dev.getAddress())) && dev.getDeviceCoordinator().supportsStepCounter(dev)) {
|
||||
final DailyTotals dailyTotals = getDailyTotals(dev, dbHandler, dashboardData.timeTo);
|
||||
@@ -186,7 +185,7 @@ public class DashboardUtils {
|
||||
public static long getActiveMinutesTotal(DashboardFragment.DashboardData dashboardData) {
|
||||
List<GBDevice> devices = GBApplication.app().getDeviceManager().getDevices();
|
||||
long totalActiveMinutes = 0;
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
try (DBHandler dbHandler = GBApplication.acquireDbReadOnly()) {
|
||||
for (GBDevice dev : devices) {
|
||||
if ((dashboardData.showAllDevices || dashboardData.showDeviceList.contains(dev.getAddress())) && dev.getDeviceCoordinator().supportsStepCounter(dev)) {
|
||||
totalActiveMinutes += getActiveMinutes(dev, dbHandler, dashboardData);
|
||||
@@ -216,7 +215,7 @@ public class DashboardUtils {
|
||||
boolean isEmptySummary = false;
|
||||
if (activitySamples != null) {
|
||||
stepSessions = stepAnalysis.calculateStepSessions(activitySamples);
|
||||
if (stepSessions.size() == 0) {
|
||||
if (stepSessions.isEmpty()) {
|
||||
isEmptySummary = true;
|
||||
}
|
||||
stepSessionsSummary = stepAnalysis.calculateSummary(stepSessions, isEmptySummary);
|
||||
|
||||
Reference in New Issue
Block a user