From 0814eb6da00703637ba3d41f3c708e08f919a448 Mon Sep 17 00:00:00 2001 From: lisonge Date: Tue, 10 Oct 2023 21:07:20 +0800 Subject: [PATCH] fix: flow map error --- .../main/java/li/songe/gkd/MainActivity.kt | 4 +- .../java/li/songe/gkd/debug/HttpService.kt | 4 +- .../li/songe/gkd/service/ManageService.kt | 52 ++++++++++--------- .../java/li/songe/gkd/shizuku/ShizukuApi.kt | 4 +- .../main/java/li/songe/gkd/util/FlowExt.kt | 15 ++++++ app/src/main/java/li/songe/gkd/util/Store.kt | 4 +- 6 files changed, 51 insertions(+), 32 deletions(-) create mode 100644 app/src/main/java/li/songe/gkd/util/FlowExt.kt diff --git a/app/src/main/java/li/songe/gkd/MainActivity.kt b/app/src/main/java/li/songe/gkd/MainActivity.kt index b6ae3d5f9..7523790ca 100644 --- a/app/src/main/java/li/songe/gkd/MainActivity.kt +++ b/app/src/main/java/li/songe/gkd/MainActivity.kt @@ -14,7 +14,6 @@ import com.dylanc.activityresult.launcher.StartActivityLauncher import com.ramcosta.composedestinations.DestinationsNavHost import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.map import li.songe.gkd.composition.CompositionActivity import li.songe.gkd.composition.CompositionExt.useLifeCycleLog import li.songe.gkd.ui.NavGraphs @@ -25,6 +24,7 @@ import li.songe.gkd.util.LocalPickContentLauncher import li.songe.gkd.util.LocalRequestPermissionLauncher import li.songe.gkd.util.UpgradeDialog import li.songe.gkd.util.launchTry +import li.songe.gkd.util.map import li.songe.gkd.util.storeFlow @AndroidEntryPoint @@ -37,7 +37,7 @@ class MainActivity : CompositionActivity({ val requestPermissionLauncher = RequestPermissionLauncher(this) lifecycleScope.launchTry(Dispatchers.IO) { - storeFlow.map { s -> s.excludeFromRecents }.collect { + storeFlow.map(lifecycleScope) { s -> s.excludeFromRecents }.collect { (app.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager).let { manager -> manager.appTasks.forEach { task -> task?.setExcludeFromRecents(it) diff --git a/app/src/main/java/li/songe/gkd/debug/HttpService.kt b/app/src/main/java/li/songe/gkd/debug/HttpService.kt index b980f6428..e015e2e54 100644 --- a/app/src/main/java/li/songe/gkd/debug/HttpService.kt +++ b/app/src/main/java/li/songe/gkd/debug/HttpService.kt @@ -27,7 +27,6 @@ import kotlinx.coroutines.cancel import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.map import kotlinx.serialization.Serializable import li.songe.gkd.app import li.songe.gkd.appScope @@ -46,6 +45,7 @@ import li.songe.gkd.service.GkdAbService import li.songe.gkd.util.Ext.getIpAddressInLocalNetwork import li.songe.gkd.util.Singleton import li.songe.gkd.util.launchTry +import li.songe.gkd.util.map import li.songe.gkd.util.storeFlow import li.songe.gkd.util.subsItemsFlow import java.io.File @@ -131,7 +131,7 @@ class HttpService : CompositionService({ var server: NettyApplicationEngine? = null scope.launchTry(Dispatchers.IO) { - storeFlow.map { s -> s.httpServerPort }.collect { port -> + storeFlow.map(scope) { s -> s.httpServerPort }.collect { port -> server?.stop() server = createServer(port).apply { start() } createNotif( diff --git a/app/src/main/java/li/songe/gkd/service/ManageService.kt b/app/src/main/java/li/songe/gkd/service/ManageService.kt index e748b3902..1f9368d10 100644 --- a/app/src/main/java/li/songe/gkd/service/ManageService.kt +++ b/app/src/main/java/li/songe/gkd/service/ManageService.kt @@ -8,8 +8,9 @@ import android.os.Build import com.blankj.utilcode.util.ScreenUtils import com.blankj.utilcode.util.ToastUtils import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import li.songe.gkd.app import li.songe.gkd.composition.CompositionExt.useLifeCycleLog @@ -23,6 +24,7 @@ import li.songe.gkd.util.VOLUME_CHANGED_ACTION import li.songe.gkd.util.appIdToRulesFlow import li.songe.gkd.util.clickCountFlow import li.songe.gkd.util.launchTry +import li.songe.gkd.util.map import li.songe.gkd.util.storeFlow class ManageService : CompositionService({ @@ -31,45 +33,47 @@ class ManageService : CompositionService({ createNotif(context, defaultChannel.id, abNotif) val scope = useScope() - val receiver = object : BroadcastReceiver() { - var lastTriggerTime = -1L - override fun onReceive(context: Context?, intent: Intent?) { - if (intent?.action == VOLUME_CHANGED_ACTION) { - val t = System.currentTimeMillis() - if (t - lastTriggerTime > 3000 && !ScreenUtils.isScreenLock()) { - lastTriggerTime = t - scope.launchTry(Dispatchers.IO) { - captureSnapshot() - ToastUtils.showShort("快照成功") + fun createReceiver(): BroadcastReceiver { + return object : BroadcastReceiver() { + var lastTriggerTime = -1L + override fun onReceive(context: Context?, intent: Intent?) { + if (intent?.action == VOLUME_CHANGED_ACTION) { + val t = System.currentTimeMillis() + if (t - lastTriggerTime > 3000 && !ScreenUtils.isScreenLock()) { + lastTriggerTime = t + scope.launchTry(Dispatchers.IO) { + captureSnapshot() + ToastUtils.showShort("快照成功") + } } } } } } - var registered = false + + var receiver: BroadcastReceiver? = null scope.launchTry(Dispatchers.IO) { - storeFlow.map { s -> s.captureVolumeChange }.collect { - registered = if (it) { - if (!registered) { + storeFlow.map(scope) { s -> s.captureVolumeChange }.collect { + if (receiver != null) { + context.unregisterReceiver(receiver) + } + receiver = if (it) { + createReceiver().apply { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { context.registerReceiver( - receiver, IntentFilter(VOLUME_CHANGED_ACTION), Context.RECEIVER_EXPORTED + this, IntentFilter(VOLUME_CHANGED_ACTION), Context.RECEIVER_EXPORTED ) } else { - context.registerReceiver(receiver, IntentFilter(VOLUME_CHANGED_ACTION)) + context.registerReceiver(this, IntentFilter(VOLUME_CHANGED_ACTION)) } } - true } else { - if (registered) { - context.unregisterReceiver(receiver) - } - false + null } } } onDestroy { - if (storeFlow.value.captureVolumeChange && registered) { + if (receiver != null) { context.unregisterReceiver(receiver) } } @@ -84,7 +88,7 @@ class ManageService : CompositionService({ } else { "暂无规则" }) + if (clickCount > 0) "/${clickCount}点击" else "" - }.collect { text -> + }.stateIn(scope, SharingStarted.Eagerly, "").collect { text -> createNotif( context, defaultChannel.id, abNotif.copy( text = text diff --git a/app/src/main/java/li/songe/gkd/shizuku/ShizukuApi.kt b/app/src/main/java/li/songe/gkd/shizuku/ShizukuApi.kt index eb71f51ff..7d8ebe04c 100644 --- a/app/src/main/java/li/songe/gkd/shizuku/ShizukuApi.kt +++ b/app/src/main/java/li/songe/gkd/shizuku/ShizukuApi.kt @@ -14,11 +14,11 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOn -import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import li.songe.gkd.composition.CanOnDestroy import li.songe.gkd.data.DeviceInfo import li.songe.gkd.util.launchWhile +import li.songe.gkd.util.map import li.songe.gkd.util.storeFlow import rikka.shizuku.Shizuku import rikka.shizuku.ShizukuBinderWrapper @@ -95,7 +95,7 @@ fun CanOnDestroy.useSafeGetTasksFc(scope: CoroutineScope): () -> List s.enableShizuku }) { shizukuAlive, shizukuGrant, enableShizuku -> + storeFlow.map(scope) { s -> s.enableShizuku }) { shizukuAlive, shizukuGrant, enableShizuku -> if (enableShizuku && shizukuAlive && shizukuGrant) newActivityTaskManager() else null }.flowOn(Dispatchers.IO).stateIn(scope, SharingStarted.Lazily, null) return { diff --git a/app/src/main/java/li/songe/gkd/util/FlowExt.kt b/app/src/main/java/li/songe/gkd/util/FlowExt.kt new file mode 100644 index 000000000..146574e7f --- /dev/null +++ b/app/src/main/java/li/songe/gkd/util/FlowExt.kt @@ -0,0 +1,15 @@ +package li.songe.gkd.util + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn + +// https://github.com/Kotlin/kotlinx.coroutines/issues/2514 +fun StateFlow.map( + coroutineScope: CoroutineScope, + mapper: (value: T) -> M, +): StateFlow = map { mapper(it) }.stateIn( + coroutineScope, SharingStarted.Eagerly, mapper(value) +) \ No newline at end of file diff --git a/app/src/main/java/li/songe/gkd/util/Store.kt b/app/src/main/java/li/songe/gkd/util/Store.kt index 03a346d3b..2ffdb7116 100644 --- a/app/src/main/java/li/songe/gkd/util/Store.kt +++ b/app/src/main/java/li/songe/gkd/util/Store.kt @@ -8,9 +8,9 @@ import android.os.Build import android.os.Parcelable import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.map import kotlinx.parcelize.Parcelize import li.songe.gkd.app +import li.songe.gkd.appScope import java.util.WeakHashMap @@ -104,7 +104,7 @@ val recordStoreFlow by lazy { } val clickCountFlow by lazy { - recordStoreFlow.map { r -> r.clickCount } + recordStoreFlow.map(appScope) { r -> r.clickCount } } fun increaseClickCount(n: Int = 1) {