EventBus3.0——基本使用

EventBus3.0——基本使用

EventBus在线程间通信有着明显的优势,普及度也非常的高,特别是升级到3.0后,使用起来更加方便、简洁,性能也得到了很好优化,并且加入了注解,其使用方式相对以前有了很大的变动,今天我就带大家来学习一下EventBus3.0的基本使用。这里针对的是以前有使用过EventBus的朋友,框架原理就不过多解释了,只贴重要部分源码。基本概念不多说,我这里以fragment之间通信为例,先上效果图:
EventBus3.0——基本使用_第1张图片
左边为fragment1、右边为fragment2,使用方法如下:

第一步、注册观察者(订阅者):

1、注册(唯一注册方法)
 @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        EventBus.getDefault().register(this);
        super.onCreate(savedInstanceState);
    }
2、解除注册
 
    
@Override
    public void onDestroyView() {
        EventBus.getDefault().unregister(this);
        super.onDestroyView();
    }

注:EventBus.getDefault()的作用是为了获取单例默认实例,register的作用是为了通过反射或者索引方式获取当前类中的注解方法,并存到Map集合中,以便post的时候使用,unregister则是释放Map集合中的缓存。

第二步、创建观察者(订阅者):

一共有四种创建观察者的方法(3.0以前版本,方法名必须如下):
onEvent:发布事件和接收事件在同一线程,不能做耗时操作,容易导致事件分发延迟。
onEventMainThread:不论事件在哪个线程中发布,接收事件只在UI线程中执行,也是最常用的订阅函数,不能做耗时操作。
onEventBackground:不论事件在哪个线程中发布,接收事件只在子线程中执行,如果事件是在子线程中发布,则接收事件直接在该子线程中执行。
onEventAsync:无论事件在哪个线程发布,都会创建新的子线程在执行onEventAsync
相信用过EventBus的朋友对这四种观察者方法都非常熟悉,但遗憾了是到了3.0的版本他们就退休了,因为引进了注解@Subscribe,我们通过源码来看一下,这个注解是怎么定义的:
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;
}
一共有三个成员变量:threadMode——线程模式(默认为ThreadMode.POSTING),sticky()——是否具备粘性,priority——优先级,相信这几个变量大家不陌生吧,3.0以前的注册函数传参是不是也有类似的参数,而且有了注解,我们在创建观察者的时候方法名也没有限制了。
那么3.0如何创建观察者呢,3.0版本通过注解描述观察者的信息,更加清晰直观的看到每个方法的线程模式、是否接受粘性消息、优先级,创建方式如下:
 
   
 @Subscribe(threadMode = ThreadMode.POSTING,priority = 1)
    public void pdmEvent(Student student) {
        if (student != null)
            tvContent.setText("onEvent " +student.getContent());
        Log.e(TAG,"onEvent: " + Thread.currentThread().getName());
    }
    @Subscribe(threadMode = ThreadMode.MAIN,priority = 2,sticky = true)
    public void pdmEventMainThread(Student student) {
        if (student != null)
            tvContent1.setText( "onEventMainThread " + student.getContent());
        Log.e(TAG,"onEventMainThread: " + student.getContent());
    }
    @Subscribe(threadMode = ThreadMode.BACKGROUND,priority = 3)
    public void pdmEventBackground(Student student) {
        Log.e(TAG,"onEventBackground: " + Thread.currentThread().getName());
    }
    @Subscribe(threadMode = ThreadMode.ASYNC,priority = 4)
    public void pdmEventAsync(Student student) {
        Log.e(TAG,"onEventAsync: " + Thread.currentThread().getName());
    }
这里源码是通过获取方法的注解来判断哪些函数是EventBus所需要的观察者方法,通过注解变量threadMode的值判断观察者的线程模式,不再需要根据方法名来判断了。源码用一个枚举来定义ThreadMode,跟原来的四种观察者函数一一对应,这样我们就不需要死死的记着那几个函数名了:
 
   
public enum ThreadMode {
    POSTING,
    MAIN,
    BACKGROUND,
    ASYNC
}

我们来看一下源码是怎么通过注解Subscribe中的属性值来决定观察者执行的线程:

 private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {//注解Subscribe的ThreadMode属性
            case POSTING://当前线程
                invokeSubscriber(subscription, event);
                break;
            case MAIN://主线程
                if (isMainThread) {
                    invokeSubscriber(subscription, event);
                } else {
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case BACKGROUND://子线程
                if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);
                } else {
                    invokeSubscriber(subscription, event);
                }
                break;
            case ASYNC://新开子线程
                asyncPoster.enqueue(subscription, event);
                break;
            default:
                throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
        }
    }

第三步、发布事件(fragment2):

@Override
    public void onListItemClick(ListView listView, View view, final int position,
                                long id) {
//        new Thread(new Runnable() {
//            @Override
//            public void run() {
                EventBus.getDefault().post(getListView().getItemAtPosition(position));
                Log.e(TAG, "run: " + Thread.currentThread().getName());
//            }
//        }).start();
        super.onListItemClick(listView, view, position, id);
    }
到了这里,EventBus的基本使用就讲完,最后我们来验证下threadMode中的四个枚举值的设置,是不是跟以前版本的四种观察者方法能够一一对应,下面看日志打印信息:
EventBus3.0——基本使用_第2张图片
明显符合,其他都没有异议,一个萝卜一个坑,但是threadMode = ThreadMode.PSTING是否跟发布事件所在线程一样,对应以前版本的onEvent方法,还有待确定,这里只能看出它在主线程运行,那么我们再将发布事件放到子线程中,来做进一步验证:
@Override
    public void onListItemClick(ListView listView, View view, final int position,
                                long id) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                EventBus.getDefault().post(getListView().getItemAtPosition(position));
                Log.e(TAG, "run: " + Thread.currentThread().getName());
            }
        }).start();
        super.onListItemClick(listView, view, position, id);
    }
默认模式的观察者也要记得修改,因为它所在线程跟发布事件线程是一样的,记得注释掉UI操作部分:
 @Subscribe(threadMode = ThreadMode.POSTING,priority = 1)
    public void pdmEvent(Student student) {
//        if (student != null)
//            tvContent.setText("onEvent " +student.getContent());
        Log.e(TAG,"onEvent: " + Thread.currentThread().getName());
    }
再看打印日志:
EventBus3.0——基本使用_第3张图片
发布事件的当前线程是Thread-146,threadMode = ThreadMode.PSTING所在方法线程也是Thread-146,到了这里最后一点疑虑也解决了,ThreadMode四个枚举值分别对应了以前版本的四种观察者方法
下一章我会就EventBus注解( @Subscribe )中stick和priority的使用做讲解。(有时间也会专门针对3.0的源码做一下阐述)
最后给没用过EventBus的朋友提供一个小demo参考:http://download.csdn.net/detail/aiyh0202/9662495




你可能感兴趣的:(EventBus,EventBus3.0使用详解)