完整代码Gitee地址:kotlin-demo: 10天Kotlin开发计划
第七天学习内容代码:Chapter7
EventBus-Kotlin
官方地址:https://github.com/greenrobot/EventBus
//build.gradle -> dependencies 引入
implementation 'org.greenrobot:eventbus:3.2.0'
EventBus原理
EventBus 是基于观察者模式,核心是事件。通过事件的发布和订阅实现组件之间的通信,EventBus默认是一个单例存在,在Java中还需要使用Synchronized来保证线程安全。
通俗来讲,EventBus通过注册将所有订阅事件的方法储存在集合中,当有事件发布的时候,根据某些规则,匹配出符合条件的方法,调用执行,从而实现组件间的通信。
发布的事件相当于被观察者,注册的对象相当于观察者,被观察者和观察者是一对多的关系。当被观察者状态发生变化,即发布事件的时候,观察者对象将会得到通知并作出响应,即执行对应的方法。
EventBus使用
使用Kotlin版本的EventBus,更方便的实现UI间通信,高性能、简单而强大,最主要是使用框架更为便捷;
举个栗子:
- 界面A->界面B 我们可以使用Intent传递
- 界面B->界面A 我们也可以使用onActivityResult接收
- 界面A->界面B->界面C,或者界面C->界面A 再使用Intent传递就太绕了
接收方必须注册与注销,在主线程订阅接收,代码如下:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//注册,重复注册会导致崩溃
EventBus.getDefault().register(this)
}
override fun onDestroy() {
super.onDestroy()
//注销,有注册就必须注销
EventBus.getDefault().unregister(this)
}
//接收消息
@Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(event: String) {
if (event == "message") {
Toast.makeText(this, "收到订阅,主界面已更新", Toast.LENGTH_SHORT).show()
button7.text = "①主界面更新"
}
}
//接收消息
@SuppressLint("SetTextI18n")
@Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(event: MessageEvent) {
when (event.type) {
MessageType.ShowLog -> {
Log.e(tag, "onMessageEvent: " + event.getString())
}
MessageType.ShowToast -> {
Toast.makeText(this, "onMessageEvent: " + event.getString(), Toast.LENGTH_SHORT).show()
button7.text = "②" + event.getString()
}
}
}
发送方,代码如下:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_learn7)
val title: TextView = findViewById(R.id.tv_title)
title.text = "组件间通信"
val butTip1: Button = findViewById(R.id.but_tip1)
butTip1.setOnClickListener {
EventBus.getDefault().post("message")
}
val butTip2: Button = findViewById(R.id.but_tip2)
butTip2.setOnClickListener {
EventBus.getDefault().post(MessageEvent(MessageType.ShowLog).put("打印日志"))
EventBus.getDefault().post(MessageEvent(MessageType.ShowToast).put("组件间通信"))
}
}
创建发送数据模型MessageEvent
private const val KEY_INT = "key_int"
private const val KEY_STRING = "key_string"
private const val KEY_BOOL = "key_bool"
private const val KEY_SERIALIZABLE = "key_serializable"
private const val KEY_PARCELABLE = "key_parcelable"
data class MessageEvent(var type: MessageType) {
var bundle = Bundle()
fun put(value: Int): MessageEvent {
bundle.putInt(KEY_INT, value)
return this
}
fun put(value: String): MessageEvent {
bundle.putString(KEY_STRING, value)
return this
}
fun put(value: Boolean): MessageEvent {
bundle.putBoolean(KEY_BOOL, value)
return this
}
fun put(value: Serializable): MessageEvent {
bundle.putSerializable(KEY_SERIALIZABLE, value)
return this
}
fun put(value: Parcelable): MessageEvent {
bundle.putParcelable(KEY_PARCELABLE, value)
return this
}
fun put(key: String, value: Int): MessageEvent {
bundle.putInt(key, value)
return this
}
fun put(key: String, value: String): MessageEvent {
bundle.putString(key, value)
return this
}
fun put(key: String, value: Boolean): MessageEvent {
bundle.putBoolean(key, value)
return this
}
fun put(key: String, value: Serializable): MessageEvent {
bundle.putSerializable(key, value)
return this
}
fun put(key: String, value: Parcelable): MessageEvent {
bundle.putParcelable(key, value)
return this
}
//===============================================================
fun getInt(): Int {
return bundle.getInt(KEY_INT)
}
fun getString(): String? {
return bundle.getString(KEY_STRING)
}
fun getBoolean(): Boolean {
return bundle.getBoolean(KEY_BOOL)
}
fun <T : Serializable> getSerializable(): Serializable {
return bundle.getSerializable(KEY_SERIALIZABLE) as T
}
fun <T : Parcelable> getParcelable(): T? {
return bundle.getParcelable<T>(KEY_PARCELABLE)
}
fun getInt(key: String): Int {
return bundle.getInt(key)
}
fun getString(key: String): String? {
return bundle.getString(key)
}
fun getBoolean(key: String): Boolean {
return bundle.getBoolean(key)
}
fun <T : Serializable> getSerializable(key: String): Serializable {
return bundle.getSerializable(key) as T
}
fun <T : Parcelable> getParcelable(key: String): T? {
return bundle.getParcelable<T>(key)
}
}
enum class MessageType {
ShowToast,
ShowLog,
}
效果展示:
事件总线功能
greenrobot 的 EventBus 的独特之处在于它的功能:
- 简单而强大: EventBus 是一个微型库,其 API 非常容易学习。然而,通过解耦组件,您的软件架构可能会受益匪浅:订阅者在使用事件时并不了解发送者。
- 实战测试: EventBus 是最常用的 Android 库之一:数以千计的应用程序使用 EventBus,包括非常流行的应用程序。超过 10 亿次应用安装不言而喻。
- 高性能:尤其是在 Android 上,性能很重要。EventBus 进行了大量分析和优化;可能使其成为同类中最快的解决方案。
- 方便的基于注解的 API (不牺牲性能):只需将 @Subscribe 注解放到您的订阅者方法中即可。由于注释的构建时索引,EventBus 不需要在您的应用程序运行时进行注释反射,这在 Android 上非常慢。
- Android 主线程传递:在与 UI 交互时,EventBus 可以在主线程中传递事件,而不管事件是如何发布的。
- 后台线程传递:如果您的订阅者执行长时间运行的任务,EventBus 还可以使用后台线程来避免 UI 阻塞。
- 事件和订阅者继承:在 EventBus 中,面向对象的范式适用于事件和订阅者类。假设事件类 A 是 B 的超类。发布的 B 类事件也将发布给对 A 感兴趣的订阅者。类似地考虑订阅者类的继承。
- 零配置: 您可以立即开始使用可从代码中的任何位置使用的默认 EventBus 实例。
- 可配置: 要根据您的要求调整 EventBus,您可以使用构建器模式调整其行为。