fix: Correctly create child coroutine scopes
This commit is contained in:
parent
8d1f92bbbe
commit
56ff5565dc
@ -4,6 +4,7 @@ import com.artemchep.keyguard.common.model.NoAnalytics
|
|||||||
import com.artemchep.keyguard.common.model.ToastMessage
|
import com.artemchep.keyguard.common.model.ToastMessage
|
||||||
import com.artemchep.keyguard.common.usecase.ShowMessage
|
import com.artemchep.keyguard.common.usecase.ShowMessage
|
||||||
import com.artemchep.keyguard.common.usecase.WindowCoroutineScope
|
import com.artemchep.keyguard.common.usecase.WindowCoroutineScope
|
||||||
|
import com.artemchep.keyguard.common.util.newChildScope
|
||||||
import com.artemchep.keyguard.platform.recordException
|
import com.artemchep.keyguard.platform.recordException
|
||||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@ -48,7 +49,7 @@ class WindowCoroutineScopeImpl(
|
|||||||
showMessage.copy(msg)
|
showMessage.copy(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val internalScope = scope + SupervisorJob() + handler
|
private val internalScope = scope.newChildScope(::SupervisorJob) + handler
|
||||||
|
|
||||||
override val coroutineContext: CoroutineContext
|
override val coroutineContext: CoroutineContext
|
||||||
get() = internalScope.coroutineContext
|
get() = internalScope.coroutineContext
|
||||||
|
@ -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)
|
@ -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.EventFlow
|
||||||
import com.artemchep.keyguard.common.util.flow.combineToList
|
import com.artemchep.keyguard.common.util.flow.combineToList
|
||||||
import com.artemchep.keyguard.common.util.flow.persistingStateIn
|
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.TextFieldModel2
|
||||||
import com.artemchep.keyguard.feature.auth.common.Validated
|
import com.artemchep.keyguard.feature.auth.common.Validated
|
||||||
import com.artemchep.keyguard.feature.auth.common.util.REGEX_US_ASCII
|
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.scan
|
||||||
import kotlinx.coroutines.flow.shareIn
|
import kotlinx.coroutines.flow.shareIn
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.plus
|
|
||||||
import org.kodein.di.compose.localDI
|
import org.kodein.di.compose.localDI
|
||||||
import org.kodein.di.direct
|
import org.kodein.di.direct
|
||||||
import org.kodein.di.instance
|
import org.kodein.di.instance
|
||||||
@ -1018,7 +1018,7 @@ fun <T, Argument> RememberStateFlowScope.foo(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (shouldAdd) {
|
if (shouldAdd) {
|
||||||
val itemCoroutineScope = screenScope + Job()
|
val itemCoroutineScope = screenScope.newChildScope(::Job)
|
||||||
val itemDefaultArg = inMemoryArguments[perst.key]
|
val itemDefaultArg = inMemoryArguments[perst.key]
|
||||||
out += Foo2Scoped(
|
out += Foo2Scoped(
|
||||||
perst = perst,
|
perst = perst,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.artemchep.keyguard.feature.navigation
|
package com.artemchep.keyguard.feature.navigation
|
||||||
|
|
||||||
import androidx.compose.runtime.staticCompositionLocalOf
|
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.BackPressInterceptorHost
|
||||||
import com.artemchep.keyguard.feature.navigation.backpress.BackPressInterceptorRegistration
|
import com.artemchep.keyguard.feature.navigation.backpress.BackPressInterceptorRegistration
|
||||||
import com.artemchep.keyguard.feature.navigation.state.FlowHolderViewModel
|
import com.artemchep.keyguard.feature.navigation.state.FlowHolderViewModel
|
||||||
@ -49,7 +50,7 @@ data class NavigationEntryImpl(
|
|||||||
) : NavigationEntry {
|
) : NavigationEntry {
|
||||||
override val type: String = route::class.simpleName.orEmpty()
|
override val type: String = route::class.simpleName.orEmpty()
|
||||||
|
|
||||||
private val job = Job()
|
private val job = Job(parent = parent.job)
|
||||||
|
|
||||||
override val scope = parent + job
|
override val scope = parent + job
|
||||||
|
|
||||||
|
@ -8,12 +8,12 @@ import com.artemchep.keyguard.common.usecase.PutScreenState
|
|||||||
import com.artemchep.keyguard.common.usecase.ShowMessage
|
import com.artemchep.keyguard.common.usecase.ShowMessage
|
||||||
import com.artemchep.keyguard.common.usecase.WindowCoroutineScope
|
import com.artemchep.keyguard.common.usecase.WindowCoroutineScope
|
||||||
import com.artemchep.keyguard.common.usecase.impl.WindowCoroutineScopeImpl
|
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.NavigationController
|
||||||
import com.artemchep.keyguard.feature.navigation.NavigationEntry
|
import com.artemchep.keyguard.feature.navigation.NavigationEntry
|
||||||
import com.artemchep.keyguard.platform.LeBundle
|
import com.artemchep.keyguard.platform.LeBundle
|
||||||
import com.artemchep.keyguard.platform.LeContext
|
import com.artemchep.keyguard.platform.LeContext
|
||||||
import com.artemchep.keyguard.platform.leBundleOf
|
import com.artemchep.keyguard.platform.leBundleOf
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.plus
|
import kotlinx.coroutines.plus
|
||||||
@ -49,9 +49,9 @@ class FlowHolderViewModel(
|
|||||||
init: RememberStateFlowScopeZygote.() -> T,
|
init: RememberStateFlowScopeZygote.() -> T,
|
||||||
): T = synchronized(this) {
|
): T = synchronized(this) {
|
||||||
store.getOrPut(key) {
|
store.getOrPut(key) {
|
||||||
val vmCoroutineScopeJob = SupervisorJob()
|
val vmCoroutineScopeJob = SupervisorJob(parent = scope.job)
|
||||||
val vmCoroutineScope = WindowCoroutineScopeImpl(
|
val vmCoroutineScope = WindowCoroutineScopeImpl(
|
||||||
scope = scope + vmCoroutineScopeJob + Dispatchers.Default,
|
scope = scope + vmCoroutineScopeJob,
|
||||||
showMessage = showMessage,
|
showMessage = showMessage,
|
||||||
)
|
)
|
||||||
val vmScope = RememberStateFlowScopeImpl(
|
val vmScope = RememberStateFlowScopeImpl(
|
||||||
@ -87,18 +87,9 @@ class FlowHolderViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var isDestroyed = false
|
|
||||||
|
|
||||||
fun destroy() {
|
fun destroy() {
|
||||||
synchronized(this) {
|
// Do nothing. We do not want to clear all of the screens
|
||||||
if (!isDestroyed) {
|
// because there still might be a screen exit animation running.
|
||||||
isDestroyed = true
|
|
||||||
//
|
|
||||||
store.keys.toSet().forEach {
|
|
||||||
clear(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun persistedState(): LeBundle {
|
fun persistedState(): LeBundle {
|
||||||
|
@ -11,6 +11,7 @@ import com.artemchep.keyguard.common.usecase.GetScreenState
|
|||||||
import com.artemchep.keyguard.common.usecase.PutScreenState
|
import com.artemchep.keyguard.common.usecase.PutScreenState
|
||||||
import com.artemchep.keyguard.common.usecase.ShowMessage
|
import com.artemchep.keyguard.common.usecase.ShowMessage
|
||||||
import com.artemchep.keyguard.common.usecase.WindowCoroutineScope
|
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.LoadingTask
|
||||||
import com.artemchep.keyguard.feature.loading.getErrorReadableMessage
|
import com.artemchep.keyguard.feature.loading.getErrorReadableMessage
|
||||||
import com.artemchep.keyguard.feature.localization.textResource
|
import com.artemchep.keyguard.feature.localization.textResource
|
||||||
@ -72,7 +73,7 @@ class RememberStateFlowScopeImpl(
|
|||||||
sink: MutableStateFlow<T>,
|
sink: MutableStateFlow<T>,
|
||||||
) {
|
) {
|
||||||
private val collectScope by lazy {
|
private val collectScope by lazy {
|
||||||
scope + Dispatchers.Main + Job()
|
scope.newChildScope(::Job) + Dispatchers.Main
|
||||||
}
|
}
|
||||||
|
|
||||||
val mutableState by lazy {
|
val mutableState by lazy {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user