EventBus的使用与深入学习

EventBus的使用与深入学习

注意:以下分析都是基于EventBus 3.0x
转载请注明出处:http://blog.csdn.net/evan_man/article/details/51328628
简单介绍
EventBus是一个用于简化Andorid、Fragment、Threads、Service之间信息传递的一个发布/订阅事件集。
传统的Android组件之间的通信方式有:Activity之间使用Intent;Service向Activity发送broadcast;Fragment和Activity之间相互持有对方的引用(随后可以调用对方的相关方法进行事件传递)。传统的事件传递的问题在于:通信方式没有实现解耦,是硬编码在组件中的。组件一旦发生修改,对应的通信方式就需要跟着修改。其实不管什么场景下,我们最好能够使得自己编写的代码最大限度的解耦,这是一个很好的习惯,避免无用功,提高代码利用率。
使用EventBus的建议:

并不建议将应用中所有的事件都通过EventBus进行发送,尤其对于一对一的组件之间通信,建议不要使用EventBus。EventBus的使用场景更像是一种广播,当我们向EventBus发送一个事件,则该事件将会传递给多个该事件的订阅者,比如Service向Activities发送事件。跟LoacalBroadCast有点近似
在Activity和Fragment中使用EventBus时,要注意在组件的生命周期开始时registered EventBus,在生命周期结束时unregistered EventBus。否则容易导致OOM;

使用EventBus的好处在于:

简化组件之间的通信方式
让业务代码更加简洁(但是需要配合相应注解进行使用)
可以指定事件处理方法的执行线程,和订阅者的优先级(跟广播类似)
足够的稳定,已经被很多Android应用使用,你绝对不是第一个吃螃蟹的人
EventBus实现了解耦,事件的创建和分发由EventBus管理,工作在一个单独的线程。EventBus的工作原理如下图:

基本使用
一、引入依赖
[java] view plain copy
在CODE上查看代码片派生到我的代码片

compile 'org.greenrobot:eventbus:3.0.0'  
provided 'org.glassfish:javax.annotation:10.0-b28' //解决获取不到@Subscribe注解的问题  

二、定义事件
[java] view plain copy
在CODE上查看代码片派生到我的代码片

public class IntentServiceResult {   
    int mResult;  
    String mResultValue;  
    IntentServiceResult(int resultCode, String resultValue) {  
        mResult = resultCode;  
        mResultValue = resultValue;  
    }  
    public int getResult() {   return mResult;  }   
    public String getResultValue() {  return mResultValue; }  
}  

三、注册EventBus
[java] view plain copy
在CODE上查看代码片派生到我的代码片

public class MainActivity extends AppCompatActivity {  
    @Override  protected void onPause() {   
        super.onPause();  
        EventBus.getDefault().unregister(this);  //注:为了后面分析的方便我们对进行注册的对象取名订阅者,如这里的MainActivity.this对象  
    }  
    @Override  protected void onResume() {   
        super.onResume();  
        EventBus.getDefault().register(this);  
    }  
}  

四、发布事件
[java] view plain copy
在CODE上查看代码片派生到我的代码片

EventBus.getDefault().post(new IntentServiceResult(24, "done!!"));  

五、创建事件处理方法
[java] view plain copy
在CODE上查看代码片派生到我的代码片

public class MainActivity extends AppCompatActivity {  
    @Subscribe(threadMode = ThreadMode.MAIN)  
    public void doThis(IntentServiceResult intentServiceResult) {  
       Toast.makeText(this, intentServiceResult.getResultValue(), Toast.LENGTH_SHORT).show();  
    }  
}  

此处的threadMode = ThreadMode.MAIN表明下面的事件处理方法在 ThreadMode.MAIN线程中执行,默认会在EventBus的工作线程中执行(发送post事件方法所在的线程)。
ThreadMode.POSTING:在和发送事件相同的线程中执行。默认的线程模式
ThreadMode.MAIN:Android的UI线程中执行。
ThreadMode.BACKGROUND:交给EventBus的一条幕后线程去执行,注意EventBus中只有一个这样的幕后线程,所以的异步方法会在这条线程中顺序执行。要求事件处理方法不要耗时太长!
ThreadMode.ASYNC:在一个单独的线程中执行,总是和发送事件的线程以及UI线程相隔离。将每个这样的事件处理方法扔到一个线程池申请一条线程进行处理。对于网络请求等可以使用这种模式!

源码学习
学习之前问问自己目的是什么,这次学习我们只是想了解以下内容

EventBus内部存储有哪些域,我们通过getDefault方法获取到的是不是它的一个单例?
EventBus的unregister和register方法内部是怎样的业务逻辑。是简单的将该对象添加一个集合,然后像Retrofit那样为每个使用了@Susbcribe标注的Method创建一个ServiceMethod?
EventBus的post方法内部的业务逻辑、是去遍历调用注册了该事件的方法来处理该事件?如何快速的找到注册了该事件的方法(Map)?
使用了@Subscribe(threadMode = ThreadMode.MAIN)标注的方法为何会在指定的线程中执行?

EventBus.class
Fields:
[java] view plain copy
在CODE上查看代码片派生到我的代码片

/*****下面的数据在EventBus自身构造器中被创建*****/  
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;   
//以事件类型为key,该事件对应的Subscription集合为value;此处使用CopyOnWrite的好处在于它是线程安全的集合,同一时间只有一个线程可以修改该集合的数据!  
private final Map<Object, List<Class<?>>> typesBySubscriber;   
//以注册EventBus的对象(该对象会接收EventBus发来的事件)为key,该对象接收的事件类型为Value  
private final Map<Class<?>, Object> stickyEvents;  
//sticky在@Subscribe标注时设置(sticky=true), sticky默认是false;直译过来是粘性事件、说人话那就是该类事件会一直被EventBus所保存,除非用户手动删除!同时从Map<Class<?>, Object>可以看出任何类型的事件只会保存一个对应的实例!  
private final HandlerPoster mainThreadPoster;          
//对应ThreadMode.MAIN模式,是一个继承Handler的类  
private final BackgroundPoster backgroundPoster;   
//对应ThreadMode.BACKGROUND模式,是一个实现了Runnable方法的类  
private final AsyncPoster asyncPoster;                   
//对应ThreadMode.ASYNC模式,是一个实现了Runnable方法的类  

/*****下面的数据都是来自EventBusBuilder*****/  
private final int indexCount;  
//一般情况为0,是EventBuilder.subscriberInfoIndexes.size()的值  
private final SubscriberMethodFinder subscriberMethodFinder;   
//订阅方法查找器负责对目标对象中使用了@Subscribe进行标注的方法进行解析得到一个SubscriberMethod对象  
private final boolean logSubscriberExceptions;  
//一般情况为true  
private final boolean logNoSubscriberMessages;  
//一般情况为true  
private final boolean sendSubscriberExceptionEvent;  
//一般情况为true  
private final boolean sendNoSubscriberEvent;  
//一般情况为true  
private final boolean throwSubscriberException;   
//一般情况为false  
private final boolean eventInheritance;  
//一般情况为true,事件是否具有传递性的标志位  
private final ExecutorService executorService;  
//执行器,对应一个Executors.newCachedThreadPool()线程池  

/*****下面的对象创建时初始化或者类加载时初始化*****/  
static volatile EventBus defaultInstance;   
//单例  
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();   
//创建EventBus对象的Builder  
private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();   
//以事件类型为key,其对应的所以父类、实现的所有接口及接口父类为value  
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {  
        @Override  protected PostingThreadState initialValue() { return new PostingThreadState(); }   
};  
//当前线程的PostingThreadState对象,之后通过get方法获取该对象  

接着我们看看使用getDefault方法得到的EventBus对象
getDefault()@EventBus.class
[java] view plain copy
在CODE上查看代码片派生到我的代码片

public static EventBus getDefault() {  
        if (defaultInstance == null) {  
            synchronized (EventBus.class) {  
                if (defaultInstance == null) {defaultInstance = new EventBus();}  
            }  
        }  
        return defaultInstance;  
}  

一个很经典的单例模式,调用EventBus的构造器创建EventBus对象;
EventBus()@EventBus.class
[java] view plain copy
在CODE上查看代码片派生到我的代码片

public EventBus() {  
        this(DEFAULT_BUILDER);  
}  
EventBus(EventBusBuilder builder) {  
        subscriptionsByEventType = new HashMap<>();  
        typesBySubscriber = new HashMap<>();  
        stickyEvents = new ConcurrentHashMap<>();  
        mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);  
        backgroundPoster = new BackgroundPoster(this);  
        asyncPoster = new AsyncPoster(this);  

        indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0; //一般情况为0  
        subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,builder.strictMethodVerification, builder.ignoreGeneratedIndex);  
        //一般情况参数为null、false、false;该对象我们后面会介绍  
        logSubscriberExceptions = builder.logSubscriberExceptions; //一般情况为true  
        logNoSubscriberMessages = builder.logNoSubscriberMessages; //一般情况为true  
        sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent; //一般情况为true  
        sendNoSubscriberEvent = builder.sendNoSubscriberEvent;//一般情况为true  
        throwSubscriberException = builder.throwSubscriberException; //一般情况为false  
        eventInheritance = builder.eventInheritance; //一般情况为true  
        executorService = builder.executorService; //一个newCachedThreadPool()  
}  

EventBusBuilder.class
Fields:
[java] view plain copy
在CODE上查看代码片派生到我的代码片

private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();    
List<SubscriberInfoIndex> subscriberInfoIndexes;  
boolean strictMethodVerification;  
boolean ignoreGeneratedIndex;  
boolean logSubscriberExceptions = true;  
boolean logNoSubscriberMessages = true;  
boolean sendSubscriberExceptionEvent = true;  
boolean sendNoSubscriberEvent = true;  
boolean throwSubscriberException;  
boolean eventInheritance = true;  
ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;  
//总结:eventInheritance、logXX和sendXX全为true;其它全为false;  

到此为止我们分析了调用getDefault方法得到的EventBus对象;
该对象存储有如下两个集合
Map

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值