diff --git a/gradle.properties b/gradle.properties index f73dc23..41bf5dc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=2.0.1 +version=2.0.2 GROUP=com.spotify.mobius diff --git a/mobius-coroutines/src/main/java/com/spotify/mobius/coroutines/CoroutinesSubtypeEffectHandlerBuilder.kt b/mobius-coroutines/src/main/java/com/spotify/mobius/coroutines/CoroutinesSubtypeEffectHandlerBuilder.kt index 82de054..7834191 100644 --- a/mobius-coroutines/src/main/java/com/spotify/mobius/coroutines/CoroutinesSubtypeEffectHandlerBuilder.kt +++ b/mobius-coroutines/src/main/java/com/spotify/mobius/coroutines/CoroutinesSubtypeEffectHandlerBuilder.kt @@ -11,9 +11,11 @@ import kotlinx.coroutines.channels.SendChannel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.flow -import java.util.concurrent.ConcurrentHashMap +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext +import kotlin.coroutines.suspendCoroutine import kotlin.reflect.KClass /** @@ -221,7 +223,8 @@ class CoroutinesSubtypeEffectHandlerBuilder { fun build(coroutineContext: CoroutineContext = EmptyCoroutineContext) = Connectable { eventConsumer -> val scope = CoroutineScope(coroutineContext) val eventsChannel = Channel() - val subEffectChannels = ConcurrentHashMap, Channel>() + val subEffectChannelsMap = mutableMapOf, Channel>() + val mutex = Mutex() // Connects the eventConsumer scope.launch { @@ -233,18 +236,26 @@ class CoroutinesSubtypeEffectHandlerBuilder { object : Connection { override fun accept(effect: F) { scope.launch { - // Creates an effectChannel if this is the first time the effect is processed - val subEffectChannel = subEffectChannels.computeIfAbsent(effect::class) { - val subEffectChannel = Channel() - val effectHandler = - effectsHandlersMap[effect::class] ?: error("No effectHandler for $effect") - // Connects the effectHandler if this is the first time the effect is processed - scope.launch { - if (isActive) effectHandler.handleEffects(subEffectChannel, eventsChannel) + val subEffectChannel = mutex.withLock { + // Prevents the creation of an effectChannel if the scope is not active + if(!isActive) return@launch + + subEffectChannelsMap.getOrPut(effect::class) { + // Creates an effectChannel the first time the effect is processed + val subEffectChannel = Channel() + val effectHandler = effectsHandlersMap[effect::class] + ?: error("No effectHandler for $effect") + // Connects the effectHandler the first time the effect is processed + scope.launch { + if (isActive) effectHandler.handleEffects( + subEffectChannel, eventsChannel + ) + } + subEffectChannel } - subEffectChannel } + // Prevents the processing of the effect if the scope is not active if (isActive) subEffectChannel.send(effect) } } @@ -252,7 +263,12 @@ class CoroutinesSubtypeEffectHandlerBuilder { override fun dispose() { scope.cancel("Effect Handler disposed") eventsChannel.close() - subEffectChannels.forEachValue(1) { it.close() } + runBlocking { + mutex.withLock { + subEffectChannelsMap.values.forEach { it.close() } + subEffectChannelsMap.clear() + } + } } } }