Skip to content

Commit 811cc8b

Browse files
committed
add wear data cache to avoid unnecessary data loads
1 parent 2a18505 commit 811cc8b

File tree

5 files changed

+67
-31
lines changed

5 files changed

+67
-31
lines changed

wear/src/main/java/com/example/util/simpletimetracker/complication/WearComplicationService.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@ class WearComplicationService : SuspendingComplicationDataSourceService() {
7575
}
7676

7777
private suspend fun buildShortTextData(): ComplicationData {
78-
val activities = wearDataRepo.loadActivities()
78+
val activities = wearDataRepo.loadActivities(forceReload = false)
7979
.getOrNull().orEmpty()
80-
val currentActivities = wearDataRepo.loadCurrentActivities()
80+
val currentActivities = wearDataRepo.loadCurrentActivities(forceReload = false)
8181
.getOrNull().orEmpty()
8282

8383
// Take most current activity.

wear/src/main/java/com/example/util/simpletimetracker/data/WearDataRepo.kt

+56-9
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,31 @@
55
*/
66
package com.example.util.simpletimetracker.data
77

8+
import android.content.ComponentName
9+
import android.content.Context
10+
import androidx.wear.watchface.complications.datasource.ComplicationDataSourceUpdateRequester
11+
import com.example.util.simpletimetracker.complication.WearComplicationService
812
import com.example.util.simpletimetracker.wear_api.WearActivity
913
import com.example.util.simpletimetracker.wear_api.WearCurrentActivity
1014
import com.example.util.simpletimetracker.wear_api.WearSettings
1115
import com.example.util.simpletimetracker.wear_api.WearTag
16+
import dagger.hilt.android.qualifiers.ApplicationContext
17+
import kotlinx.coroutines.Deferred
18+
import kotlinx.coroutines.async
19+
import kotlinx.coroutines.awaitAll
1220
import kotlinx.coroutines.channels.BufferOverflow
21+
import kotlinx.coroutines.coroutineScope
1322
import kotlinx.coroutines.flow.MutableSharedFlow
1423
import kotlinx.coroutines.flow.SharedFlow
1524
import kotlinx.coroutines.flow.asSharedFlow
25+
import kotlinx.coroutines.sync.Mutex
26+
import kotlinx.coroutines.sync.withLock
1627
import javax.inject.Inject
1728
import javax.inject.Singleton
1829

1930
@Singleton
2031
class WearDataRepo @Inject constructor(
32+
@ApplicationContext private val context: Context,
2133
private val wearRPCClient: WearRPCClient,
2234
) {
2335

@@ -28,31 +40,66 @@ class WearDataRepo @Inject constructor(
2840
onBufferOverflow = BufferOverflow.DROP_OLDEST,
2941
)
3042

43+
private var activitiesCache: List<WearActivity>? = null
44+
private var currentActivitiesCache: List<WearCurrentActivity>? = null
45+
private val mutex: Mutex = Mutex()
46+
3147
init {
32-
wearRPCClient.addListener { _dataUpdated.emit(Unit) }
48+
wearRPCClient.addListener {
49+
coroutineScope {
50+
val deferred = mutableListOf<Deferred<Any>>()
51+
deferred += async { loadActivities(forceReload = true) }
52+
deferred += async { loadCurrentActivities(forceReload = true) }
53+
deferred.awaitAll()
54+
updateComplications()
55+
_dataUpdated.emit(Unit)
56+
}
57+
}
3358
}
3459

35-
suspend fun loadActivities(): Result<List<WearActivity>> {
36-
return runCatching { wearRPCClient.queryActivities() }
60+
suspend fun loadActivities(
61+
forceReload: Boolean,
62+
): Result<List<WearActivity>> = mutex.withLock {
63+
return runCatching {
64+
activitiesCache.takeUnless { forceReload }
65+
?: wearRPCClient.queryActivities()
66+
.also { activitiesCache = it }
67+
}
3768
}
3869

39-
suspend fun loadCurrentActivities(): Result<List<WearCurrentActivity>> {
40-
return runCatching { wearRPCClient.queryCurrentActivities() }
70+
suspend fun loadCurrentActivities(
71+
forceReload: Boolean,
72+
): Result<List<WearCurrentActivity>> = mutex.withLock {
73+
return runCatching {
74+
currentActivitiesCache.takeUnless { forceReload }
75+
?: wearRPCClient.queryCurrentActivities()
76+
.also { currentActivitiesCache = it }
77+
}
4178
}
4279

43-
suspend fun setCurrentActivities(starting: List<WearCurrentActivity>): Result<Unit> {
80+
suspend fun setCurrentActivities(starting: List<WearCurrentActivity>): Result<Unit> = mutex.withLock {
4481
return runCatching { wearRPCClient.setCurrentActivities(starting) }
4582
}
4683

47-
suspend fun loadTagsForActivity(activityId: Long): Result<List<WearTag>> {
84+
suspend fun loadTagsForActivity(activityId: Long): Result<List<WearTag>> = mutex.withLock {
4885
return runCatching { wearRPCClient.queryTagsForActivity(activityId) }
4986
}
5087

51-
suspend fun loadSettings(): Result<WearSettings> {
88+
suspend fun loadSettings(): Result<WearSettings> = mutex.withLock {
5289
return runCatching { wearRPCClient.querySettings() }
5390
}
5491

55-
suspend fun openAppPhone(): Result<Unit> {
92+
suspend fun openAppPhone(): Result<Unit> = mutex.withLock {
5693
return runCatching { wearRPCClient.openPhoneApp() }
5794
}
95+
96+
fun updateComplications() {
97+
ComplicationDataSourceUpdateRequester.create(
98+
context = context,
99+
complicationDataSourceComponent = ComponentName(
100+
context,
101+
WearComplicationService::class.java,
102+
),
103+
).requestUpdateAll()
104+
}
58105
}

wear/src/main/java/com/example/util/simpletimetracker/data/WearMessenger.kt

-11
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,8 @@
55
*/
66
package com.example.util.simpletimetracker.data
77

8-
import android.content.ComponentName
98
import android.content.Context
109
import android.util.Log
11-
import androidx.wear.watchface.complications.datasource.ComplicationDataSourceUpdateRequester
12-
import com.example.util.simpletimetracker.complication.WearComplicationService
1310
import com.example.util.simpletimetracker.wear_api.WearRequests
1411
import com.google.android.gms.tasks.Tasks
1512
import com.google.android.gms.wearable.CapabilityClient
@@ -78,7 +75,6 @@ class WearMessenger @Inject constructor(
7875
when (path) {
7976
WearRequests.DATA_UPDATED -> {
8077
listener?.invoke()
81-
updateComplications()
8278
}
8379
else -> {
8480
Log.d(tag, "$path is an invalid RPC call")
@@ -88,13 +84,6 @@ class WearMessenger @Inject constructor(
8884
return null
8985
}
9086

91-
private fun updateComplications() {
92-
ComplicationDataSourceUpdateRequester.create(
93-
context = context,
94-
complicationDataSourceComponent = ComponentName(context, WearComplicationService::class.java),
95-
).requestUpdateAll()
96-
}
97-
9887
private fun findNearestNode(capability: String): Node? {
9988
// Find all nodes which support the time tracking message
10089
Log.d(tag, "Searching for nodes with ${context.packageName} installed")

wear/src/main/java/com/example/util/simpletimetracker/domain/CurrentActivitiesMediator.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class CurrentActivitiesMediator @Inject constructor(
2828
.getOrNull() ?: return Result.failure(WearRPCException)
2929

3030
return if (settings.allowMultitasking) {
31-
val currents = wearDataRepo.loadCurrentActivities()
31+
val currents = wearDataRepo.loadCurrentActivities(forceReload = false)
3232
.getOrNull() ?: return Result.failure(WearRPCException)
3333
wearDataRepo.setCurrentActivities(currents.plus(newCurrent))
3434
} else {
@@ -37,7 +37,7 @@ class CurrentActivitiesMediator @Inject constructor(
3737
}
3838

3939
suspend fun stop(currentId: Long): Result<Unit> {
40-
val currents = wearDataRepo.loadCurrentActivities()
40+
val currents = wearDataRepo.loadCurrentActivities(forceReload = false)
4141
.getOrNull() ?: return Result.failure(WearRPCException)
4242
val remaining = currents.filter { it.id != currentId }
4343
return wearDataRepo.setCurrentActivities(remaining)

wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/activities/ActivitiesViewModel.kt

+7-7
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ class ActivitiesViewModel @Inject constructor(
4343

4444
fun init() {
4545
if (isInitialized) return
46-
loadData()
4746
subscribeToDataUpdates()
4847
isInitialized = true
4948
}
@@ -63,17 +62,18 @@ class ActivitiesViewModel @Inject constructor(
6362
if (result.isFailure) showError()
6463
}
6564

66-
fun onRefresh() {
67-
loadData()
65+
fun onRefresh() = viewModelScope.launch {
66+
loadData(forceReload = true)
67+
wearDataRepo.updateComplications()
6868
}
6969

7070
fun onOpenOnPhone() = viewModelScope.launch {
7171
wearDataRepo.openAppPhone()
7272
}
7373

74-
private fun loadData() = viewModelScope.launch {
75-
val activities = wearDataRepo.loadActivities()
76-
val currentActivities = wearDataRepo.loadCurrentActivities()
74+
private suspend fun loadData(forceReload: Boolean) {
75+
val activities = wearDataRepo.loadActivities(forceReload)
76+
val currentActivities = wearDataRepo.loadCurrentActivities(forceReload)
7777

7878
when {
7979
activities.isFailure || currentActivities.isFailure -> {
@@ -97,7 +97,7 @@ class ActivitiesViewModel @Inject constructor(
9797

9898
private fun subscribeToDataUpdates() {
9999
viewModelScope.launch {
100-
wearDataRepo.dataUpdated.collect { loadData() }
100+
wearDataRepo.dataUpdated.collect { loadData(forceReload = false) }
101101
}
102102
}
103103

0 commit comments

Comments
 (0)