Skip to content

Commit f86d000

Browse files
committed
better SingleEventChannel
1 parent ff9c8de commit f86d000

File tree

1 file changed

+26
-13
lines changed

1 file changed

+26
-13
lines changed

sample/app/src/main/java/com/hoc081098/channeleventbus/sample/android/common/SingleEventChannel.kt

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.hoc081098.channeleventbus.sample.android.common
22

33
import androidx.annotation.MainThread
4-
import com.hoc081098.channeleventbus.sample.android.BuildConfig
4+
import androidx.lifecycle.ViewModel
55
import java.io.Closeable
66
import java.lang.System.identityHashCode
77
import kotlin.LazyThreadSafetyMode.NONE
@@ -10,11 +10,22 @@ import kotlinx.coroutines.channels.onClosed
1010
import kotlinx.coroutines.channels.onFailure
1111
import kotlinx.coroutines.channels.onSuccess
1212
import kotlinx.coroutines.flow.Flow
13+
import kotlinx.coroutines.flow.FlowCollector
1314
import kotlinx.coroutines.flow.emitAll
14-
import kotlinx.coroutines.flow.flow
1515
import kotlinx.coroutines.flow.receiveAsFlow
1616
import timber.log.Timber
1717

18+
sealed interface SingleEventFlow<E> : Flow<E> {
19+
/**
20+
* Must collect in [Dispatchers.Main.immediate][kotlinx.coroutines.MainCoroutineDispatcher.immediate].
21+
* Safe to call in the coroutines launched by [androidx.lifecycle.lifecycleScope].
22+
*
23+
* In Compose, we can use [CollectWithLifecycleEffect] with `inImmediateMain = true`.
24+
*/
25+
@MainThread
26+
override suspend fun collect(collector: FlowCollector<E>)
27+
}
28+
1829
@MainThread
1930
interface HasSingleEventFlow<E> {
2031
/**
@@ -23,7 +34,7 @@ interface HasSingleEventFlow<E> {
2334
*
2435
* In Compose, we can use [CollectWithLifecycleEffect] with `inImmediateMain = true`.
2536
*/
26-
val singleEventFlow: Flow<E>
37+
val singleEventFlow: SingleEventFlow<E>
2738
}
2839

2940
@MainThread
@@ -35,23 +46,21 @@ sealed interface SingleEventFlowSender<E> {
3546
suspend fun sendEvent(event: E)
3647
}
3748

49+
private class SingleEventFlowImpl<E>(private val channel: Channel<E>) : SingleEventFlow<E> {
50+
override suspend fun collect(collector: FlowCollector<E>) {
51+
debugCheckImmediateMainDispatcher()
52+
return collector.emitAll(channel.receiveAsFlow())
53+
}
54+
}
55+
3856
@MainThread
3957
class SingleEventChannel<E> :
4058
Closeable,
4159
HasSingleEventFlow<E>,
4260
SingleEventFlowSender<E> {
4361
private val _eventChannel = Channel<E>(Channel.UNLIMITED)
4462

45-
override val singleEventFlow: Flow<E> by lazy(NONE) {
46-
if (BuildConfig.DEBUG) {
47-
flow {
48-
debugCheckImmediateMainDispatcher()
49-
emitAll(_eventChannel.receiveAsFlow())
50-
}
51-
} else {
52-
_eventChannel.receiveAsFlow()
53-
}
54-
}
63+
override val singleEventFlow: SingleEventFlow<E> by lazy(NONE) { SingleEventFlowImpl(_eventChannel) }
5564

5665
init {
5766
Timber.d("[EventChannel] created: hashCode=${identityHashCode(this)}")
@@ -78,3 +87,7 @@ class SingleEventChannel<E> :
7887
Timber.d("[EventChannel] closed: hashCode=${identityHashCode(this)}")
7988
}
8089
}
90+
91+
@Suppress("NOTHING_TO_INLINE")
92+
inline fun <E> SingleEventChannel<E>.addToViewModel(viewModel: ViewModel) =
93+
apply { viewModel.addCloseable(this) }

0 commit comments

Comments
 (0)