首先说为什么不用EventBus,是因为他用到了反射,而这么简单的功能我觉得是没必要用反射的,其次就是为了一个事件要写很多方法,而如果要达到EventBus的效果其实代码是很简单的,所以我就自己写了一个事件分发器。代码如下:
package com.liuhc.library.event
import androidx.annotation.UiThread
import org.jetbrains.annotations.TestOnly
import java.lang.ref.ReferenceQueue
import java.lang.ref.WeakReference
typealias CallBack<T> = (T) -> Unit
/// author:liuhaichao
/// description: 数据监听类
/// create date: 2020-10-12 on 5:08 PM
object DataListener {
//事件,"监听者和该事件对应的回调"列表
private val map: MutableMap<Class<*>, MutableList<CallbackSoftReference>> = mutableMapOf()
private val queue = ReferenceQueue<Any>()
/**
* @param listener 监听者
* @param eventClass 要监听的类型
* @param callback 收到事件后会回调该方法
*/
@Suppress("UNCHECKED_CAST")
@UiThread
@JvmStatic
fun <T> listen(listener: Any, eventClass: Class<T>, callback: CallBack<T>) {
clearQueue()
if (!map.containsKey(eventClass)) {
map[eventClass] = mutableListOf()
}
val list = map[eventClass]!!
val transformCallback: (Any) -> Unit = { callback(it as T) }
if (!list.contains(listener)) {
list.add(CallbackSoftReference(listener, transformCallback, queue))
}
}
/**
* @param event 要发送的事件
*/
@UiThread
@JvmStatic
fun publish(event: Any) {
clearQueue()
val eventToCallbackList = map[event::class.java]
eventToCallbackList?.forEach {
it.callBack(event)
}
}
/**
* @param listener 监听者
* 在页面销毁的时候必须调用,防止内存泄漏,建议写到Activity或者Fragment的onDestroy方法里
*/
@UiThread
@JvmStatic
fun destroy(listener: Any) {
destroy(listener.hashCode())
}
@UiThread
@JvmStatic
private fun destroy(listenerHashCode: Int) {
clearQueue()
val entryIterator = map.entries.iterator()
while (entryIterator.hasNext()) {
val entry = entryIterator.next()
val list = entry.value
val listIterator = list.iterator()
while (listIterator.hasNext()) {
val callbackSoftReference = listIterator.next()
if (callbackSoftReference.listenerHashcode == listenerHashCode) {
listIterator.remove()
}
if (list.isEmpty()) {
entryIterator.remove()
}
}
}
}
private fun clearQueue() {
var callbackSoftReference: CallbackSoftReference?
while (true) {
callbackSoftReference = queue.poll() as? CallbackSoftReference
if (callbackSoftReference == null) {
break
}
destroy(callbackSoftReference.listenerHashcode)
}
}
private class CallbackSoftReference(listener: Any, val callBack: CallBack<Any>, queue: ReferenceQueue<Any>) :
WeakReference<Any>(listener, queue) {
val listenerHashcode = listener.hashCode()
}
@TestOnly
fun isEmpty(): Boolean {
clearQueue()
return map.isEmpty()
}
}
使用方法
//在onCreate或onStart里注册
DataListener.listen(this, String::class.java) {
println(it)
}
//发布事件
DataListener.publish("abc")
//在onDestroy或onStop里解绑
DataListener.destroy(this)
代码其实是很简单的,主要是用到了软引用。使用方法可以在onCreate里注册,在onDestroy里解绑,或者在onStart里注册,在onStop里解绑。
如果在onStart和onStop里分别注册和解绑的话,那我们在页面onStop后就接收不到事件了,如果在onCreate里注册在onDestroy里解绑的话,我们知道Activity在被系统回收的时候onDestroy方法是不一定会调用的,所以像EventBus解绑不及时就会导致内存泄漏。所以我这里增加了软引用,即使没有解绑成功,在内存不足的时候页面也可以被正常回收,但是这只是兜底方案,正常使用还是应该在父类的onDestroy里调用DataListener.destroy(this),不要等到内存不足才被系统回收。