Android应用内组件通讯之EventBus的使用(一)

这周本来想再输出一篇vsomeip协议栈的服务提供流程源码分析的,无奈流程以及其中的状态太过于复杂,还在梳理中,于是准备水一篇应用内通讯组件EventBus来缓解一下疲累的心情(梳理源码的流程过于心累),之所以挑准了EventBus,是结合了实际工作过程中的场景:车机内部的进程间通信,以及应用内的组件通信的频率很高。准备后续就这方面来进行一些流程的优化开发,所以预先借助分析EventBus的使用方式,设计思想,以及源码实现来构造自己的通信组件SDK。

说了那么多废话,下面进入正题,看下官网上提供的一个通信架构图,EventBus采用的是一个观察者模式设计,事件发布者提交事件给到总线,总线再将事件分发给订阅者。
Android应用内组件通讯之EventBus的使用(一)_第1张图片

集成方式

在工程模块的build.gradle文件中添加如下依赖配置:

dependencies {
    implementation 'org.greenrobot:eventbus:3.3.1'
    ...
    ...
}

API

EventBus的源码量很少,API也很少,下面来分别来介绍下:

  • 注册监听与反注册
    每个模块需要监听数据时需要调用EventBus的register传入当前模块的引用,当模块退出时,需要调用unregister方法解注册,不然的话,当前模块无法被回收,后果就是造成内存泄漏。模块中需要定义全域可见的方法,并使用@Subscribe方法来标记,作为模块中接收事件的回调函数。函数定义如下:

register(注册)

    /**
     * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
     * are no longer interested in receiving events.
     * 

* Subscribers have event handling methods that must be annotated by {@link Subscribe}. * The {@link Subscribe} annotation also allows configuration like {@link * ThreadMode} and priority. */ public void register(Object subscriber)

unregister(反注册)

    /** Unregisters the given subscriber from all event classes. */
    public synchronized void unregister(Object subscriber) 

Subscribe(订阅方法注解)

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
    ThreadMode threadMode() default ThreadMode.POSTING;

    /**
     * If true, delivers the most recent sticky event (posted with
     * {@link EventBus#postSticky(Object)}) to this subscriber (if event available).
     */
    boolean sticky() default false;

    /** Subscriber priority to influence the order of event delivery.
     * Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before
     * others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of
     * delivery among subscribers with different {@link ThreadMode}s! */
    int priority() default 0;
}

使用Activity来举个例子

class TestActivity : AppCompatActivity() {
    override fun onStart() {
        super.onStart()
        //注册当前模块为监听器
        EventBus.getDefault().register(this)
    }

    override fun onStop() {
        super.onStop()
        //解注册模块
        EventBus.getDefault().unregister(this)
    }

    //定义监听回调方法,方法可见为全局的pulic方法,方法执行在Main函数中,优先级为1000,且监听的事件类型为粘性事件
    @Subscribe(threadMode = ThreadMode.MAIN, priority = 1000, sticky = true)
    fun eventObserver(event: Event1?){
        Log.i("eventbus", "seconds Received: ${data1.v0}")
    }
}

上述定义后,只要有其他模块提交数据类型为Data1的事件,eventObserver方法就会在主线程中被执行,我们就可以在函数中处理对应的数据; 当然我们也可以让eventObserver函数运行在子线程中,只需要改变注解中的threadMode值即可。EventBus是根据@SubScribe所注解的函数参数来查找该模块所监听的参数,如果模块需要监听总线上所有的数据,则修改函数入参的类型为Any(Java语言为Object), 如果需要监听某一类型的数据,则需要定义数据类型与子数据,然后修改入参即可。

data class Event0(val data0 : Int, val data1 : Int)
open class Event1(data0 : Int, data1 : Int)
class SubEvent(data0: Int, data1: Int, name:String = "SubEvent") : Event1(data0, data1)
class SubEvent1(data0: Int, data1: Int, data2:Int, name: String = "SubEvent") : Event1(data0, data1)

上述Demo中可以监听类型为Event1, SubEvent, SubEvent1的数据

  • Event处理
    event类型分为两种,普通事件与粘性事件,顾名思义,普通事件就是发布事件,然后给已经订阅的模块消费事件,如果模块订阅发生在事件发布之后,则该模块无法获取到该事件;粘性事件 就是一个长期存在于消息总线的事件,粘性事件发生后,只要模块注册完成,即可得到该事件。EventBus提供两个函数来发布事件: post用来发布普通事件,postSticky用来发布粘性事件。
    /** Posts the given event to the event bus. */
    public void post(Object event) 
    /**
     * Posts the given event to the event bus and holds on to the event (because it is sticky). The most recent sticky
     * event of an event's type is kept in memory for future access by subscribers using {@link Subscribe#sticky()}.
     */
    public void postSticky(Object event)

演示代码:

private var i : Boolean = false
findViewById<Button>(R.id.post_data).setOnClickListener {
    EventBus.getDefault().post(if(i) SubEvent(0,0) else SubEvent1(1,1, 1))
    EventBus.getDefault().postSticky(if(i) SubEvent(0,0) else SubEvent1(1,1, 1))
    i = i.not()
}
  • 其他操作

终止事件处理

    /**
     * Called from a subscriber's event handling method, further event delivery will be canceled. Subsequent
     * subscribers
     * won't receive the event. Events are usually canceled by higher priority subscribers (see
     * {@link Subscribe#priority()}). Canceling is restricted to event handling methods running in posting thread
     * {@link ThreadMode#POSTING}.
     */
    public void cancelEventDelivery(Object event)

移除粘性事件


    /**
     * Remove and gets the recent sticky event for the given event type.
     *
     * @see #postSticky(Object)
     */
    public <T> T removeStickyEvent(Class<T> eventType)
    
    
    /**
     * Removes the sticky event if it equals to the given event.
     *
     * @return true if the events matched and the sticky event was removed.
     */
    public boolean removeStickyEvent(Object event)
    
    /**
     * Removes all sticky events.
     */
    public void removeAllStickyEvents()

获取消息总线中的粘性事件

    /**
     * Gets the most recent sticky event for the given type.
     *
     * @see #postSticky(Object)
     */
    public <T> T getStickyEvent(Class<T> eventType)

模块订阅状态

 public synchronized boolean isRegistered(Object subscriber)

查找某事件类型是否有订阅模块

 public boolean hasSubscriberForEvent(Class<?> eventClass)

总结

回顾一下,在Android应用开发过程中,EventBus解决了Android应用开发过程中各个模块中通信问题,且内部提供了指定线程类型来处理事务的机制,让我们处理事件更加方便,事件类型与订阅者的类型不受限制,更加灵活。 但是它并不是完美的,就类似于注册与反注册这两步来说,如果开发者稍不注意,注册之后,没有调用反注册,那就一定会引起订阅模块的对象无法释放,进而造成内存泄漏等问题,所以我看现在有一个更新的替代方案:LiveDataBus,LiveDataBus结合了jetpack中组件的LifeCycle来规避了监听对象因生命周期而造成内存泄漏的问题,这个后续有空再写一篇聊聊。下一篇去看看EventBus源码,学习优秀的开源库,有利于身心健康。

你可能感兴趣的:(android应用开发,android)