前言
Jetpack Compose并没有提供组件之间的事件交互,这里我们可以使用flow自定义一个EventBus来实现。
工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import kotlinx.coroutines.* import kotlinx.coroutines.flow.* import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import java.util.concurrent.ConcurrentHashMap
object ZFlowEventBus { private val eventFlows = ConcurrentHashMap<Class<*>, MutableSharedFlow<Any>>()
private val mutex = Mutex()
suspend fun <T : Any> post(event: T) { val flow = eventFlows.getOrPut(event::class.java) { MutableSharedFlow(replay = 0) } flow.emit(event) }
suspend fun <T : Any> postSticky(event: T) { val flow = eventFlows.getOrPut(event::class.java) { MutableSharedFlow(replay = 1) } flow.emit(event) }
fun <T : Any> subscribe( lifecycleOwner: LifecycleOwner, eventType: Class<T>, dispatcher: CoroutineDispatcher = Dispatchers.Main, block: suspend (T) -> Unit, ) { lifecycleOwner.lifecycleScope.launch { lifecycleOwner.repeatOnLifecycle(Lifecycle.State.CREATED) { val flow = eventFlows.getOrPut(eventType) { MutableSharedFlow(replay = if (eventType.isAnnotationPresent(Sticky::class.java)) 1 else 0) } as MutableSharedFlow<T>
flow.collect { event -> withContext(dispatcher) { block(event) } } } } }
suspend fun <T : Any> removeEvent(event: T) { mutex.withLock { eventFlows.remove(event::class.java) } }
@OptIn(ExperimentalCoroutinesApi::class) suspend fun <T : Any> removeStickyEvent(eventType: Class<T>) { mutex.withLock { eventFlows[eventType]?.let { flow -> flow.resetReplayCache() } } } }
@Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) annotation class Sticky
|
定义事件
1 2 3 4 5 6 7 8 9
| class ZEventSelectSubject()
data class ZEventSelectSubjectCb(val subjectId: String)
@Sticky data class ZEventThemeChanged(val theme: String)
|
订阅事件
1 2 3 4 5 6
| lifecycleScope.launch { ZFlowEventBus.subscribe(lifecycleOwner, ZEventSelectSubjectCb::class.java) { event -> } }
|
Compose组件内使用
1 2 3 4 5 6 7 8 9
| val lifecycleOwner = LocalLifecycleOwner.current LaunchedEffect(Unit) { ZFlowEventBus.subscribe( lifecycleOwner, ZEventSelectSubject::class.java, block = { vm.showSubjectDialog.value = true } ) }
|
带参数的
1 2 3 4 5 6 7 8 9 10 11 12 13
| val lifecycleOwner = LocalLifecycleOwner.current LaunchedEffect(Unit) { ZFlowEventBus.subscribe( lifecycleOwner, ZEventSelectSubjectCb::class.java ) { ZFlowEventBus.removeEvent(it) navController.navigate( MyScreen.ScreenMistakeQuesGaopin.createRoute( it.subjectId ) ) } }
|
接收到事件后记得移除事件
1
| ZFlowEventBus.removeEvent(it)
|
发送事件
1 2 3 4 5 6 7 8 9
| viewModelScope.launch { ZFlowEventBus.post(ZEventSelectSubjectCb("123")) }
viewModelScope.launch { ZFlowEventBus.postSticky(ZEventThemeChanged("Dark")) }
|
Composable 组件中
1 2 3 4
| val coroutineScope = rememberCoroutineScope() coroutineScope.launch { ZFlowEventBus.post(ZEventSelectSubject()) }
|
移除事件
1 2 3 4
| lifecycleScope.launch { ZFlowEventBus.removeStickyEvent(ZEventThemeChanged::class.java) }
|