Skip to content

Commit 1eff557

Browse files
authored
Merge pull request #177 from juanmrivero/coroutines-removeJava8-usages
Remove ConcurrentHashMap to avoid Java8 problems on Android phones
2 parents c4fc618 + f4be350 commit 1eff557

File tree

2 files changed

+29
-13
lines changed

2 files changed

+29
-13
lines changed

gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version=2.0.1
1+
version=2.0.2
22

33
GROUP=com.spotify.mobius
44

mobius-coroutines/src/main/java/com/spotify/mobius/coroutines/CoroutinesSubtypeEffectHandlerBuilder.kt

+28-12
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ import kotlinx.coroutines.channels.SendChannel
1111
import kotlinx.coroutines.flow.Flow
1212
import kotlinx.coroutines.flow.FlowCollector
1313
import kotlinx.coroutines.flow.flow
14-
import java.util.concurrent.ConcurrentHashMap
14+
import kotlinx.coroutines.sync.Mutex
15+
import kotlinx.coroutines.sync.withLock
1516
import kotlin.coroutines.CoroutineContext
1617
import kotlin.coroutines.EmptyCoroutineContext
18+
import kotlin.coroutines.suspendCoroutine
1719
import kotlin.reflect.KClass
1820

1921
/**
@@ -221,7 +223,8 @@ class CoroutinesSubtypeEffectHandlerBuilder<F : Any, E : Any> {
221223
fun build(coroutineContext: CoroutineContext = EmptyCoroutineContext) = Connectable { eventConsumer ->
222224
val scope = CoroutineScope(coroutineContext)
223225
val eventsChannel = Channel<E>()
224-
val subEffectChannels = ConcurrentHashMap<KClass<out F>, Channel<F>>()
226+
val subEffectChannelsMap = mutableMapOf<KClass<out F>, Channel<F>>()
227+
val mutex = Mutex()
225228

226229
// Connects the eventConsumer
227230
scope.launch {
@@ -233,26 +236,39 @@ class CoroutinesSubtypeEffectHandlerBuilder<F : Any, E : Any> {
233236
object : Connection<F> {
234237
override fun accept(effect: F) {
235238
scope.launch {
236-
// Creates an effectChannel if this is the first time the effect is processed
237-
val subEffectChannel = subEffectChannels.computeIfAbsent(effect::class) {
238-
val subEffectChannel = Channel<F>()
239-
val effectHandler =
240-
effectsHandlersMap[effect::class] ?: error("No effectHandler for $effect")
241-
// Connects the effectHandler if this is the first time the effect is processed
242-
scope.launch {
243-
if (isActive) effectHandler.handleEffects(subEffectChannel, eventsChannel)
239+
val subEffectChannel = mutex.withLock {
240+
// Prevents the creation of an effectChannel if the scope is not active
241+
if(!isActive) return@launch
242+
243+
subEffectChannelsMap.getOrPut(effect::class) {
244+
// Creates an effectChannel the first time the effect is processed
245+
val subEffectChannel = Channel<F>()
246+
val effectHandler = effectsHandlersMap[effect::class]
247+
?: error("No effectHandler for $effect")
248+
// Connects the effectHandler the first time the effect is processed
249+
scope.launch {
250+
if (isActive) effectHandler.handleEffects(
251+
subEffectChannel, eventsChannel
252+
)
253+
}
254+
subEffectChannel
244255
}
245-
subEffectChannel
246256
}
247257

258+
// Prevents the processing of the effect if the scope is not active
248259
if (isActive) subEffectChannel.send(effect)
249260
}
250261
}
251262

252263
override fun dispose() {
253264
scope.cancel("Effect Handler disposed")
254265
eventsChannel.close()
255-
subEffectChannels.forEachValue(1) { it.close() }
266+
runBlocking {
267+
mutex.withLock {
268+
subEffectChannelsMap.values.forEach { it.close() }
269+
subEffectChannelsMap.clear()
270+
}
271+
}
256272
}
257273
}
258274
}

0 commit comments

Comments
 (0)