fix: Correctly create child coroutine scopes

This commit is contained in:
Artem Chepurnoy 2024-02-27 21:26:56 +02:00
parent 8d1f92bbbe
commit 56ff5565dc
No known key found for this signature in database
GPG Key ID: FAC37D0CF674043E
6 changed files with 25 additions and 19 deletions

View File

@ -4,6 +4,7 @@ import com.artemchep.keyguard.common.model.NoAnalytics
import com.artemchep.keyguard.common.model.ToastMessage
import com.artemchep.keyguard.common.usecase.ShowMessage
import com.artemchep.keyguard.common.usecase.WindowCoroutineScope
import com.artemchep.keyguard.common.util.newChildScope
import com.artemchep.keyguard.platform.recordException
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
@ -48,7 +49,7 @@ class WindowCoroutineScopeImpl(
showMessage.copy(msg)
}
private val internalScope = scope + SupervisorJob() + handler
private val internalScope = scope.newChildScope(::SupervisorJob) + handler
override val coroutineContext: CoroutineContext
get() = internalScope.coroutineContext

View File

@ -0,0 +1,12 @@
package com.artemchep.keyguard.common.util
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.plus
val CoroutineScope.job
get() = coroutineContext[Job]
inline fun CoroutineScope.newChildScope(
builder: (Job?) -> Job,
): CoroutineScope = this + builder(job)

View File

@ -16,6 +16,7 @@ import com.artemchep.keyguard.common.usecase.CipherUnsecureUrlCheck
import com.artemchep.keyguard.common.util.flow.EventFlow
import com.artemchep.keyguard.common.util.flow.combineToList
import com.artemchep.keyguard.common.util.flow.persistingStateIn
import com.artemchep.keyguard.common.util.newChildScope
import com.artemchep.keyguard.feature.auth.common.TextFieldModel2
import com.artemchep.keyguard.feature.auth.common.Validated
import com.artemchep.keyguard.feature.auth.common.util.REGEX_US_ASCII
@ -54,7 +55,6 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.scan
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.plus
import org.kodein.di.compose.localDI
import org.kodein.di.direct
import org.kodein.di.instance
@ -1018,7 +1018,7 @@ fun <T, Argument> RememberStateFlowScope.foo(
}
}
if (shouldAdd) {
val itemCoroutineScope = screenScope + Job()
val itemCoroutineScope = screenScope.newChildScope(::Job)
val itemDefaultArg = inMemoryArguments[perst.key]
out += Foo2Scoped(
perst = perst,

View File

@ -1,6 +1,7 @@
package com.artemchep.keyguard.feature.navigation
import androidx.compose.runtime.staticCompositionLocalOf
import com.artemchep.keyguard.common.util.job
import com.artemchep.keyguard.feature.navigation.backpress.BackPressInterceptorHost
import com.artemchep.keyguard.feature.navigation.backpress.BackPressInterceptorRegistration
import com.artemchep.keyguard.feature.navigation.state.FlowHolderViewModel
@ -49,7 +50,7 @@ data class NavigationEntryImpl(
) : NavigationEntry {
override val type: String = route::class.simpleName.orEmpty()
private val job = Job()
private val job = Job(parent = parent.job)
override val scope = parent + job

View File

@ -8,12 +8,12 @@ import com.artemchep.keyguard.common.usecase.PutScreenState
import com.artemchep.keyguard.common.usecase.ShowMessage
import com.artemchep.keyguard.common.usecase.WindowCoroutineScope
import com.artemchep.keyguard.common.usecase.impl.WindowCoroutineScopeImpl
import com.artemchep.keyguard.common.util.job
import com.artemchep.keyguard.feature.navigation.NavigationController
import com.artemchep.keyguard.feature.navigation.NavigationEntry
import com.artemchep.keyguard.platform.LeBundle
import com.artemchep.keyguard.platform.LeContext
import com.artemchep.keyguard.platform.leBundleOf
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.plus
@ -49,9 +49,9 @@ class FlowHolderViewModel(
init: RememberStateFlowScopeZygote.() -> T,
): T = synchronized(this) {
store.getOrPut(key) {
val vmCoroutineScopeJob = SupervisorJob()
val vmCoroutineScopeJob = SupervisorJob(parent = scope.job)
val vmCoroutineScope = WindowCoroutineScopeImpl(
scope = scope + vmCoroutineScopeJob + Dispatchers.Default,
scope = scope + vmCoroutineScopeJob,
showMessage = showMessage,
)
val vmScope = RememberStateFlowScopeImpl(
@ -87,18 +87,9 @@ class FlowHolderViewModel(
}
}
private var isDestroyed = false
fun destroy() {
synchronized(this) {
if (!isDestroyed) {
isDestroyed = true
//
store.keys.toSet().forEach {
clear(it)
}
}
}
// Do nothing. We do not want to clear all of the screens
// because there still might be a screen exit animation running.
}
fun persistedState(): LeBundle {

View File

@ -11,6 +11,7 @@ import com.artemchep.keyguard.common.usecase.GetScreenState
import com.artemchep.keyguard.common.usecase.PutScreenState
import com.artemchep.keyguard.common.usecase.ShowMessage
import com.artemchep.keyguard.common.usecase.WindowCoroutineScope
import com.artemchep.keyguard.common.util.newChildScope
import com.artemchep.keyguard.feature.loading.LoadingTask
import com.artemchep.keyguard.feature.loading.getErrorReadableMessage
import com.artemchep.keyguard.feature.localization.textResource
@ -72,7 +73,7 @@ class RememberStateFlowScopeImpl(
sink: MutableStateFlow<T>,
) {
private val collectScope by lazy {
scope + Dispatchers.Main + Job()
scope.newChildScope(::Job) + Dispatchers.Main
}
val mutableState by lazy {