跨页面通信是一个比较常见的场景,通常我们会选择使用EventBus
,但EventBus
无法感知生命周期,收到消息就会回调,所以有了LiveData
之后很快就有了LiveEventBus
。不过它也有缺点,比如不能切换接收线程。现在SharedFlow稳定了,那是不是也能搞一波?
于是有了FlowEventBus
通过学习 从?LiveData
?迁移到 Kotlin 数据流 ?得到思路:
SharedFlow
作为事件载体 :
优点:
结合?Lifecycle
?感知生命周期,做到响应时机可控 。不仅可以全局范围的事件,也可以单页面内的通信而不透传到别的页面,如:Activity内部
,Fragment
内部通信。
关键在于?kotlinx-coroutines > 1.4.x
??和?lifecycle-runtime-ktx > 2.3.x
以下示例中的Event
均是随意定义的类,只是测试时为了区分事件而定义的名字
//全局范围
postEvent(AppScopeEvent("form?TestFragment"))
//Fragment?内部范围?
postEvent(fragment,FragmentEvent("form?TestFragment"))
//Activity?内部范围
postEvent(requireActivity(),ActivityEvent("form?TestFragment"))
复制代码
事件监听
//接收?Activity?Scope事件
observeEvent<ActivityEvent>(scope?=?requireActivity())?{
????...
}
//接收?Fragment?Scope事件
observeEvent<FragmentEvent>(scope?=?fragment)?{
????...
}
//接收?App?Scope事件
observeEvent<AppScopeEvent>?{
????...
}
Like ObserveForever:
//此时需要指定协程范围
observeEvent<GlobalEvent>(scope?=?coroutineScope)?{
???????...
}
postEvent(CustomEvent(value?=?"Hello?Word"),1000)
复制代码
线程切换
observeEvent<ActivityEvent>(Dispatchers.IO)?{
????...
}
observeEvent<ActivityEvent>(minActiveState?=?Lifecycle.State.DESTROYED)?{
???...
}
observeEvent<GlobalEvent>(isSticky?=?true)?{
???...
}
removeStickyEvent(StickyEvent::class.java)
?removeStickyEvent(fragment,StickyEvent::class.java)
?removeStickyEvent(activity,StickyEvent::class.java)
以上功能依托于Kotlin协程的SharedFlow
和Lifecycle
?因此实现起来非常简单。
MutableSharedFlow<Any>(
????replay?=?if?(isSticky)?1?else?0,
????extraBufferCapacity?=?Int.MAX_VALUE?//避免挂起导致数据发送失败
)
fun?<T>?LifecycleOwner.launchWhenStateAtLeast(
????minState:?Lifecycle.State,
????block:?suspend?CoroutineScope.()?->?T
)?{
????lifecycleScope.launch?{
????????lifecycle.whenStateAtLeast(minState,?block)
????}
}
whenStateAtLeast
?由于执行的block
默认是在主线程,因此需要手动切换线程:
lifecycleOwner.launchWhenStateAtLeast(minState)?{
????flow.collect?{?value?->
????????lifecycleOwner.lifecycleScope.launch(dispatcher)?{
????????????????onReceived.invoke(value?as?T)
????????}
????}
}
viewModelScope.launch?{
????delay(time)
????flow.emit(value)
}
Flow本身就是有序的
使用全局ViewModel
,主要是因为有ViewModelScope
,可以避免使用GlobalScope
,如果想要单页面内部组件通信,那就使用ActivityScope的ViewModel
就行了:
object?ApplicationScopeViewModelProvider?:?ViewModelStoreOwner?{
????private?val?eventViewModelStore:?ViewModelStore?=?ViewModelStore()
????override?fun?getViewModelStore():?ViewModelStore?{
????????return?eventViewModelStore
????}
????private?val?mApplicationProvider:?ViewModelProvider?by?lazy?{
????????ViewModelProvider(
????????????ApplicationScopeViewModelProvider,
????????????ViewModelProvider.AndroidViewModelFactory.getInstance(EventBusInitializer.application)
????????)
????}
????fun?<T?:?ViewModel>?getApplicationScopeViewModel(modelClass:?Class<T>):?T?{
????????return?mApplicationProvider[modelClass]
????}
}
ViewModel
内部有2个map
,分别是粘性和非粘性:
internal?class?EventBusViewModel?:?ViewModel()?{
????private?val?eventFlows:?HashMap<String,?MutableSharedFlow<Any>>?=?HashMap()
????private?val?stickyEventFlows:?HashMap<String,?MutableSharedFlow<Any>>?=?HashMap()
????...
}
Android高级开发系统进阶笔记、最新面试复习笔记PDF,我的GitHub
对文章有何见解,或者有何技术问题,欢迎在评论区一起留言讨论!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。