Short step without thousands of miles, not small streams into rivers and seas. There is no need to hear what other people say about this, this, that, that, that, it feels very lofty topic, when you have a solid foundation, everything will be natural.Copy the code

Pro tip: This was written by a colleague of mine who wrote a simple library with very little code after looking at the source code distributed by Android. What problem was it trying to solve? When a page has a lot of EditTexts and I need validation when I click the submit button, when I send an event and any child View (EditText) consumes it, the validation fails and the current submission cannot be made, and Toast pops up to tell the user why the submission failed. Some people say, well, I could have done it in other ways, yeah, in many ways, but it’s not how I did it, it’s the way it worked, using the source code for the project. Next, I’ll introduce you to this short library.

Interface IEventInterceptor {// select handleEvent(eventId: Int, data: Any?) based on eventId and specific data. : Boolean }Copy the code
Interface IEventDispatcher: IEventInterceptor {fun dispatchEvent(eventId: Int, data: Any?) : Boolean fun dispatchDown(eventId: Int, data: Any?) : Boolean // Child views do not consume events, nor do they consume themselves or their siblings, events pass up fun dispatchUp(eventId: Int, data: Any?) Fun addChild(eventDispatcher: IEventDispatcher) Fun removeChild(eventDispatcher: IEventDispatcher) IEventDispatcher) fun getChildren(): List<WeakReference<IEventDispatcher>>? Fun getInterceptors(): List<WeakReference<IEventInterceptor>>? fun addInterceptor(interceptors: IEventInterceptor) fun removeInterceptor(interceptors: IEventInterceptor) // Set the parent View fun setParent(parent: IEventDispatcher?) }Copy the code
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()
        }
    }
}
Copy the code

Analysis 1: When I see this method block, I am confused, ask a colleague a question: why the current View can not handle, directly throw his father is not good, the chain of responsibility should not be like this, why I still need to pay attention to the sibling node and the parent View? He said to reduce complexity, the parent View just throw up, also makes sense, in fact, contact event distribution, is not difficult to implement, you can think about it.