Android-事件分发-学习产出

296 阅读4分钟
不积跬步无以至千里,不积小流无以成江海。没有必要听到别人说什么这这那那,感觉很高大上的话题,当你基础一切扎实之后,一切都是水到渠成。

小贴士:这个是我同事写的,他看完Android分发的源码之后,手写的一个简单的库,代码很少,但是确实很巧。当时是为了解决一个什么问题呢?当一个页面有很多的EditText,当我点击提交按钮的时候需要校验,当我发送了一个事件,一旦有子View(EditText)消费了,就证明有一项校验没有通过,那么当前就不能提交,并弹出Toast,告诉用户为啥不能提交成功。有人说,我其他方式也能实现,是的,方式很多,我纠结的不是怎么实现,而是这个实现的方式很巧,把源代码用到工程。接下来,我给大家介绍一下这个简短的库。



interface IEventInterceptor {
    // 根据事件ID,和具体的数据,来选择处理事件
    fun handleEvent(eventId: Int, data: Any?): Boolean
}
interface IEventDispatcher : IEventInterceptor {
    // 分发事件相关方法
    
    // 正常的分发事件
    fun dispatchEvent(eventId: Int, data: Any?): Boolean
    // 向子View先分发事件
    fun dispatchDown(eventId: Int, data: Any?): Boolean
    // 子View不消费事件,自己以及兄弟节点也不消费,事件往上传递
    fun dispatchUp(eventId: Int, data: Any?): Boolean
    
    // 子View相关方法
    fun addChild(eventDispatcher: IEventDispatcher)
    fun removeChild(eventDispatcher: IEventDispatcher)
    fun getChildren(): List<WeakReference<IEventDispatcher>>?
    
    // 拦截器相关
    fun getInterceptors(): List<WeakReference<IEventInterceptor>>?
    fun addInterceptor(interceptors: IEventInterceptor)
    fun removeInterceptor(interceptors: IEventInterceptor)
    
    // 设置当前View的父View
    fun setParent(parent: IEventDispatcher?)
}
class EventDispatcherImpl : IEventDispatcher {

    // 父分发器
    private var mDispatcherParent: IEventDispatcher? = null
    
    // 子View分发
    private val mDispatcherChildren: CopyOnWriteArrayList<WeakReference<IEventDispatcher>> by lazy {
        CopyOnWriteArrayList<WeakReference<IEventDispatcher>>()
    }
    
    // 拦截器(拦截器也是有可能消费事件的,对传统的事件分发进行了扩展)
    private val mInterceptors: CopyOnWriteArrayList<WeakReference<IEventInterceptor>> by lazy {
        CopyOnWriteArrayList<WeakReference<IEventInterceptor>>()
    }
    
    // 当前View处理器,自己对事件的处理
    private var mEvenDispatcherPoxy: IEventInterceptor
    
    // 子View集合,用弱引用,当子View销毁之后,不用手动remove,会自动销毁,销毁之后会进到这个queue
    private val childrenReferenceQueue: ReferenceQueue<IEventDispatcher> by lazy {
        ReferenceQueue<IEventDispatcher>()
    }
    
    // 拦截器集合,同样弱引用,当拦截器销毁,销毁之后会进去这个queue
    private val interceptorsReferenceQueue: ReferenceQueue<IEventInterceptor> by lazy {
        ReferenceQueue<IEventInterceptor>()
    }

    constructor(eventDispatcher: IEventDispatcher) {
        mEvenDispatcherPoxy = eventDispatcher
    }

    constructor(eventDispatcher: IEventDispatcher, parent: IEventDispatcher?) {
        mEvenDispatcherPoxy = eventDispatcher
        this.mDispatcherParent = parent
        this.mDispatcherParent?.let { it.addChild(this) }
    }

    // 设置当前“View”的父亲,联系起来
    override fun setParent(parent: IEventDispatcher?) {
        this.mDispatcherParent = parent
        this.mDispatcherParent?.let {
            it.addChild(this)
        }
    }

    // 当前View处理事件,首先拦截器处理,拦截器不处理,就自己来处理,很好理解
    override fun handleEvent(eventId: Int, data: Any?): Boolean {
        if (mInterceptors != null) {
            cleanInterceptorsReferenceIfNeed()
            for (interceptor in mInterceptors) {
                val ref = interceptor.get()
                val isHandled = ref?.handleEvent(eventId, data) ?: false
                if (isHandled) {
                    return isHandled
                }
            }
        }
        return mEvenDispatcherPoxy.handleEvent(eventId, data)
    }

    // 这个是事件分发的入口,开始分发事件,刚开始把事件分发给孩子,孩子不处理,把事件向上分发
    override fun dispatchEvent(eventId: Int, data: Any?): Boolean {
        val isHandled = dispatchDown(eventId, data)
        return if (isHandled) true else dispatchUp(eventId, data)
    }

    // 事件向下分发,发给子View
    override fun dispatchDown(eventId: Int, data: Any?): Boolean {
        // 判断是不是有子View销毁了,如果销毁了,就remove掉
        cleanDispatcherReferenceIfNeed()
        // 遍历子View,看看是不是有子View处理事件
        for (item in mDispatcherChildren) {
            val ref = item.get()
            if (ref != null) {
                val handled = ref.dispatchDown(eventId, data)
                if (handled) {
                    return true
                }
            }
        }
        // 如果子View不处理,就自己来处理
        return handleEvent(eventId, data)
    }

    // 分析一
    // 子View和自己都不处理,事件向上抛
    override fun dispatchUp(eventId: Int, data: Any?): Boolean {
        val dispatcher = mDispatcherParent ?: return false
        val children: List<WeakReference<IEventDispatcher>>? = dispatcher.getChildren()
        // 看看当前View的兄弟节点是不是会处理事件
        if (children != null) {
            for (child in children) {
                val ref = child.get()
                if (ref != null && ref !== this && ref.dispatchDown(eventId, data)) {
                    return true
                }
            }
        }
        val eventInterceptors: List<WeakReference<IEventInterceptor>>? = mDispatcherParent?.getInterceptors()
        // 判断父View的拦截器是不是可以处理事件
        if (eventInterceptors != null) {
            for (child in eventInterceptors) {
                val ref = child.get()
                if (ref != null && ref !== this && ref.handleEvent(eventId, data)) {
                    return true
                }
            }
        }
        // 当前父View是否处理事件
        val handled = dispatcher.handleEvent(eventId, data)
        // 当前父View处理就返回true,否则继续往上抛
        return if (handled) {
            true
        } else dispatcher.dispatchUp(eventId, data)
    }

    override fun addChild(eventDispatcher: IEventDispatcher) {
        if (contain<IEventDispatcher>(mDispatcherChildren, eventDispatcher) < 0) {
            mDispatcherChildren.add(WeakReference<IEventDispatcher>(eventDispatcher, childrenReferenceQueue))
        }
        cleanDispatcherReferenceIfNeed()
    }

    // 移除一个子View
    override fun removeChild(eventDispatcher: IEventDispatcher) {
        var index: Int
        if (contain<IEventDispatcher>(mDispatcherChildren, eventDispatcher).apply { index = this } >= 0) {
            mDispatcherChildren.removeAt(index)
        }
    }

    override fun getChildren(): List<WeakReference<IEventDispatcher>>? {
        cleanDispatcherReferenceIfNeed()
        return mDispatcherChildren
    }

    override fun getInterceptors(): List<WeakReference<IEventInterceptor>>? {
        cleanInterceptorsReferenceIfNeed()
        return mInterceptors
    }

    override fun addInterceptor(interceptor: IEventInterceptor) {
        if (contain<IEventInterceptor>(this.mInterceptors, interceptor) < 0) {
            this.mInterceptors.add(
                WeakReference(interceptor, interceptorsReferenceQueue)
            )
        }
        cleanInterceptorsReferenceIfNeed()
    }

    override fun removeInterceptor(interceptor: IEventInterceptor) {

        var index: Int
        if (contain<IEventInterceptor>(this.mInterceptors, interceptor).apply { index = this } >= 0) {
            this.mInterceptors.removeAt(index)
        }
    }

    fun getParent(): IEventDispatcher? {
        return mDispatcherParent
    }

    private fun <T> contain(refList: List<WeakReference<T>>?, obj: T): Int {
        var index = -1
        if (refList.isNullOrEmpty()) {
            return index
        }
        for (item in refList) {
            index++
            val ref = item.get()
            if (ref != null && ref === obj) {
                return index
            }
        }
        return -1
    }

    // 清除销毁的子View
    private fun cleanDispatcherReferenceIfNeed() {
        innerCleanReferenceQueue(childrenReferenceQueue, mDispatcherChildren)
    }

    // 清除销毁的拦截器
    private fun cleanInterceptorsReferenceIfNeed() {
        innerCleanReferenceQueue(interceptorsReferenceQueue, mInterceptors)
    }

    private fun innerCleanReferenceQueue(referenceQueue: ReferenceQueue<*>?, targetList: MutableList<*>?) {
        if (targetList == null || referenceQueue == null) {
            return
        }
        var reference = referenceQueue.poll()
        while (reference != null) {
            if (targetList.contains(reference)) {
                targetList.remove(reference)
            }
            reference = referenceQueue.poll()
        }
    }
}

分析一:当我看到这个方法块的时候,我比较疑惑,问了同事一个问题:为啥当前View处理不了,直接抛给他的父亲不就好了,责任链不应该就是这样的吗,为哈我还需要关注兄弟节点和父View呢?他说是为了减少复杂度,父View只管往上抛就行,也说的通吧,其实联系事件分发,也不难实现的,大家可以自己思考一下。