perf: 优化数据存储逻辑

This commit is contained in:
lisonge 2023-11-09 16:19:09 +08:00
parent 1c7df7e751
commit df39f35317

View File

@ -1,81 +1,47 @@
package li.songe.gkd.util package li.songe.gkd.util
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import com.blankj.utilcode.util.LogUtils import com.blankj.utilcode.util.LogUtils
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import li.songe.gkd.app
import li.songe.gkd.appScope import li.songe.gkd.appScope
import java.util.WeakHashMap
private val onReceives by lazy {
mutableListOf<(
context: Context?,
intent: Intent?,
) -> Unit>()
}
private val receiver by lazy {
object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
onReceives.forEach { fc -> fc(context, intent) }
}
}.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
app.registerReceiver(this, IntentFilter(app.packageName), Context.RECEIVER_NOT_EXPORTED)
} else {
app.registerReceiver(this, IntentFilter(app.packageName))
}
}
}
val stateFlowToKey by lazy { WeakHashMap<StateFlow<*>, String>() }
private inline fun <reified T> createStorageFlow( private inline fun <reified T> createStorageFlow(
key: String, key: String,
crossinline init: () -> T, crossinline init: () -> T,
): StateFlow<T> { ): StateFlow<T> {
val stateFlow = val str = kv.getString(key, null)
MutableStateFlow(kv.getString(key, null)?.let { Singleton.json.decodeFromString<T>(it) } val initValue = if (str != null) {
?: init()) try {
onReceives.add { _, intent -> Singleton.json.decodeFromString<T>(str)
val extras = intent?.extras ?: return@add } catch (e: Exception) {
val type = extras.getString("type") ?: return@add e.printStackTrace()
val itKey = extras.getString("key") ?: return@add LogUtils.d(e)
if (type == "update_storage" && itKey == key) { null
stateFlow.value = }
kv.getString(key, null)?.let { Singleton.json.decodeFromString<T>(it) } ?: init() } else {
null
}
val stateFlow = MutableStateFlow(initValue ?: init())
appScope.launch {
stateFlow.drop(1).collect {
withContext(Dispatchers.IO) {
kv.encode(key, Singleton.json.encodeToString(it))
}
} }
} }
stateFlowToKey[stateFlow] = key
return stateFlow return stateFlow
} }
fun <T> updateStorage(stateFlow: StateFlow<T>, newState: T) {
fun sendStorageBroadcast(key: String) { (stateFlow as MutableStateFlow).value = newState
app.sendBroadcast(Intent(app.packageName).apply {
`package` = app.packageName
putExtra("type", "update_storage")
putExtra("key", key)
})
} }
inline fun <reified T> updateStorage(stateFlow: StateFlow<T>, newState: T) {
if (stateFlow.value == newState) return
val key = stateFlowToKey[stateFlow] ?: error("not found stateFlow key")
kv.encode(key, Singleton.json.encodeToString(newState))
sendStorageBroadcast(key)
}
@Serializable @Serializable
data class Store( data class Store(
val enableService: Boolean = true, val enableService: Boolean = true,
@ -113,6 +79,8 @@ val clickCountFlow by lazy {
recordStoreFlow.map(appScope) { r -> r.clickCount } recordStoreFlow.map(appScope) { r -> r.clickCount }
} }
private val log2FileSwitchFlow by lazy { storeFlow.map(appScope) { s -> s.log2FileSwitch } }
fun increaseClickCount(n: Int = 1) { fun increaseClickCount(n: Int = 1) {
updateStorage( updateStorage(
recordStoreFlow, recordStoreFlow,
@ -121,11 +89,10 @@ fun increaseClickCount(n: Int = 1) {
} }
fun initStore() { fun initStore() {
receiver
storeFlow.value storeFlow.value
recordStoreFlow.value recordStoreFlow.value
appScope.launchTry(Dispatchers.IO) { appScope.launchTry(Dispatchers.IO) {
storeFlow.map(appScope) { s -> s.log2FileSwitch }.collect { log2FileSwitchFlow.collect {
LogUtils.getConfig().isLog2FileSwitch = it LogUtils.getConfig().isLog2FileSwitch = it
} }
} }