伊夫ntBus全深入分析连串(一)

作者:ca88编程

标题1:伊夫ntBus这么轻便,有如何毛病吗?

跟奇骏xJava相比,就是缺乏对事件的拍卖和再分发。它一贯new三个事变,然后发表,你不能对事件张开管理。

透过上一篇文章《EventBus 3.0相知恨晚》对伊芙ntBus3.0的准绳及使用格局有了简短询问。

EventBus特性

  • 简言之易用的依据注脚的API:轻便地把@Subscribe评释放在您的订阅方法后面就可以。通过编写翻译期的订阅者索引,app无需在运营期做注脚反射。
  • 支撑事件投递到Android主线程:当订阅者要求和UI做交互的时候,伊芙ntBus能发送事件到主线程中去,而不管该事件是从哪个线程中发出来的。
  • 支撑事件投递到后台线程:当订阅者必要做耗费时间使命时,EventBus能发送事件到后台线程中去,幸免梗塞主线程。
  • 扶持事件&订阅者世襲关系:在伊芙ntBus中,面向对象也被运用到事件和订阅者类中。比方,事件类A是事件类B的父类,那时候,发送B类型的事件,该事件也会发送给对于事件类A感兴趣的订阅者。对于订阅者类,也存在日常的继续关系。
  • 零设定就可以使用:没有必要别的设定,在您代码的此外市方,使用一个现存的私下认可的伊芙ntBus实例对象,你就足以初阶工作了。
  • 可配备:使用建造者情势,你能够调治伊芙ntBus的一颦一笑,使之知足你的须求。

类型地址:EventBus,本文分析版本: 3.1.1

ca88编程 1EventBus脑图

sticky的意义###

本条单词sticky的情趣是粘贴性,这里的野趣就是在出殡和安葬事件过后再订阅该事件也能接到该事件
默认为false。

EventBus优点

  • 简化组件之间的通讯
  • 解耦事件的发送者和选用者
  • 很好的选用于Activity之间,Fragment之间,后台线程之间的通讯,幸免使用intent只怕handler所带来的复杂度
  • 能够制止复杂的,易于出错的依赖性和生命周期难点
  • 速度快,尤其是在做了优化以往
  • 轻量 (大概 50k 的jar包)
  • 被有100,000,000 安装量的洋洋app 在实质上接纳中证实
  • 有成都百货上千高档特性,比如多样类型的线程情势,subscriber的优先级,等等

三、实现

具体步骤

加多信赖库

 compile 'org.greenrobot:eventbus:3.0.0'

概念事件

事件只是叁个POJO(plain old java object,Java原始类型),未有特定的必要。

public class MessageEvent { public final String message; public MessageEvent(String message) { this.message = message; }}

思考订阅者

接受表明的措施,内定方法运行的线程 ,参数决定选用的平地风波,方法名自由,提出由on 事件名组成。

ThreadMode

  • ThreadMode.POSTING:跟公布事件的线程一致
  • ThreadMode.MAIN:在主线程中运作
  • ThreadMode.BACKGROUND:在后台线程中运转(非主线程则直接运维,否则新开三个线程运营)
  • ThreadMode.ASYNC:在异步线程中运转(不管post线程,笔者正是要新开一个线程运转)
@Subscribe(threadMode = ThreadMode.MAIN)public void onMessageEvent(MessageEvent event) { Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();}

进而,在适度的时候注册事件,并在适龄的时候解注册事件

@Overridepublic void onStart() { super.onStart(); EventBus.getDefault().register;}@Overridepublic void onStop() { EventBus.getDefault().unregister; super.onStop();}

出殡事件

能够在此外市方发送事件,然后注册了平地风波的地点就能够摄取啦~

EventBus.getDefault().post(new MessageEvent("Hello everyone!"));

priority 的意义###

本条priority的含义是优先级,这里首要说一下定论和注意事项

  • 刚开始阶段级高(priority值大)的将会首先选择到揭橥者所揭露的平地风波
  • 刚开始阶段级只是照准于同一的ThreadMode中
  • 默许的优先级为0

ca88编程,日常应用时,能够依照实际供给做调度。

参考

  1. EventBus官网
  2. EventBus github
  3. EventBus官方文书档案
  4. EventBus作者blog
  5. EventBus3.0公布表达
  6. Eventbus API Doc

2.1 增加信任

消除思路

ca88编程 2EventBus的设计思路

接纳事件总线的publisher/subscriber格局举行解耦,消除组件间通讯和四线程难题

四种threadMode模式###

  • ThreadMode: POSTING
      当时订阅者实行的线程与事件的公布者所在的线程为同二个线程。相当于说事件由哪个线程公布的,订阅者就在哪些线程中实施。这几个也是伊芙ntBus暗中同意的线程方式;由于并未有线程的切换,也就意味着消耗的财富也是小小的的。固然叁个职分无需多线程的,也是引进应用这种ThreadMode的。

我们前边的德姆o就是那般,事件发送是在SecondActivity的主线程,那么onMessage伊夫nt在暗中认可意况下一定会将会在主线程实行。

  • ThreadMode: MAIN
      从它的名字就超级轻松能够观望,他是在Android的主线程中运维的。如若提交的线程也是主线程,那么她就和ThreadMode.POSTING同样了。当然在这里边由于是在主线程中运作的,所以在这里间就无法进行一些耗费时间的天职。

要么事前的德姆o,大家在SecondActivity中落到实处登陆操作,寻常意况下这一定是个互连网央求,而这么些网络诉求必然不会在主线程(UI线程)中生出,所以,当大家完结网络央浼发布事件的时候,发布事件所在的线程就不再是UI线程了,大家的onMessage伊夫nt的ThreadMode就不能够为暗中认可值,必须内定为MAIN,确定保证其在主线程进行对UI的操作。

  • **ThreadMode: BACKGROUND **
      这种情势下,大家的订阅者将会在后台线程中施行。倘使公布者是在主线程中开展的风云发布,那么订阅者将会重新展开叁个子线程运转,假设公布者在不是在主线程中开展的风云宣布,那么那时候订阅者就在公布者所在的线程中进行任务。

这种场合,日常是大家须要在订阅者方法中张开耗时的操作。

  • ThreadMode: ASYNC
      在这里种方式下,订阅者将会单独运维在一个线程中。不管公布者是在主线程仍旧在子线程中举办事件的发表,订阅者都以在重新展开一个线程来实施任务。

此间大家得以简轻易单的测量试验一下,加深驾驭:

上边代码用4种不同的Thread格局订阅相近事件MessageEvent

@Subscribe(threadMode = ThreadMode.PostThread)
public void onMessageEventPostThread(MessageEvent messageEvent) {
    Log.e("PostThread", Thread.currentThread().getName());
}

@Subscribe(threadMode = ThreadMode.MainThread)
public void onMessageEventMainThread(MessageEvent messageEvent) {
    Log.e("MainThread", Thread.currentThread().getName());
}

@Subscribe(threadMode = ThreadMode.BackgroundThread)
public void onMessageEventBackgroundThread(MessageEvent messageEvent) {
    Log.e("BackgroundThread", Thread.currentThread().getName());
}

@Subscribe(threadMode = ThreadMode.Async)
public void onMessageEventAsync(MessageEvent messageEvent) {
    Log.e("Async", Thread.currentThread().getName());
}
  • 在主线程发表事件:
Log.e("postEvent", Thread.currentThread().getName());
EventBus.getDefault().post(new MessageEvent());

看一下日志输出:

主线程中透露事件

能够看到,在主线程揭橥事件,那么Post和Main 格局下,订阅者方法也是在主线程实践,其他两种情势下独家是单身的线程。

  • 在子线程公布事件
new Thread(new Runnable() {
                @Override
                public void run() {
                    Log.e("postEvent", Thread.currentThread().getName());
                    EventBus.getDefault().post(new MessageEvent());
                }
            }).start();

看一下日志输出:

子线程公布事件

子线程发表事件时,只有ThreadMode 为MAIN时,订阅者方法才会在主线程推行。其他都以在单身的线程。

EventBus 3.0与2.x的区别

1.包名例外

  • EventBus 2.x

de.greenrobot.event

  • EventBus 3.0

org.greenrobot.eventbus

2.订阅方法

  • EventBus 2.x:
    行使一定的法子名标记订阅方法,方法名也代表了threadMode

on伊芙nt(卡塔尔国 —— POST线程,订阅方法运维在公布者所在的线程
onEventMainThread() —— UI主线程,订阅方法运维在主线程
onEventBackground(卡塔尔 —— 后台线程,公布者是主线程,订阅方法运维在新开子线程;发布者是子线程,订阅方法运维在宣布者所在的线程;
onEventAsync(卡塔尔国 —— 异步线程,订阅方法运维在新开子线程,无论发表者是在哪些线程

  • EventBus 3.0:
    运用注脚来标志订阅方法。同时能够钦赐threadMode,代表订阅方法所运营的线程;内定sticky,代表是还是不是是粘性事件;钦赐priority,代表优先级。
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.POSTING —— POST线程,订阅方法运行在公布者所在的线程(暗中同意)
ThreadMode.MAIN —— UI主线程,订阅方法运维在主线程
ThreadMode.BACKGROUND —— 后台线程,发布者是主线程,订阅方法运营在新开子线程;公布者是子线程,订阅方法运维在发表者所在的线程;
ThreadMode.ASYNC —— 异步线程,订阅方法运维在新开子线程,无论公布者是在哪些线程

sticky,与Android广播机制中的sticky概念同样。即在订阅者注册从前,便早就把事件发送出去,等到注册之后,订阅者便会采用前段时间出殡的粘性事件。注意是最近,即重复发送同一种等级次序的粘性事件,订阅者只可以收到最后一条。

priority,当事件发送后,钦点多少个订阅者收到事件的顺序

    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true, priority = 10)
    public void onEvent(EventBusEvent eventBusEvent) {
        tv.setText(eventBusEvent.info);
    }

3.参数配置的颗粒度

  • EventBus 2.x:
    priority 和 stickyness 仅仅以类为单位进行安顿,反逼该类中保有订阅方法一定要共享同一配置
  • EventBus 3.0 :
    priority 和 stickyness 以艺术为单位张开安顿,颗粒度越来越细,显著越来越灵活

4.质量进级

  • EventBus 2.x:
    运作时,使用反射的办法来寻找回调方法,品质极慢
  • EventBus 3.0:
    提供了EventBusAnnotationProcessor注明微型机,能够在编写翻译期读取@Subscribe(卡塔尔注脚而且剖判当中所满含的音讯,以供运转时直接利用,进而运维时的属性大大提升了

3.2.1 通过反射管理申明

SubscriberMethodFinder#findUsingReflection

private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
    FindState findState = prepareFindState();
    findState.initForSubscriber(subscriberClass);
    while (findState.clazz != null) {
        findUsingReflectionInSingleClass(findState);
        findState.moveToSuperclass();
    }
    return getMethodsAndRelease(findState);
}

SubscriberMethodFinder#findUsingReflectionInSingleClass

private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {
            // This is faster than getMethods, especially when subscribers are fat classes like Activities
            methods = findState.clazz.getDeclaredMethods();//获取的是类的所有公有方法,这就包括自身 和从基类继承的、从接口实现的所有 public 方法。
            //getDeclareMethods 返回的是该类中定义的「所有方法」,但是不包括从父类继承而来的方法
        } catch (Throwable th) {
            methods = findState.clazz.getMethods();
            findState.skipSuperClasses = true;
        }
        for (Method method : methods) {//遍历方法
            int modifiers = method.getModifiers();
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length == 1) {//参数列表长度为 0
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                    if (subscribeAnnotation != null) {
                        Class<?> eventType = parameterTypes[0];
                        if (findState.checkAdd(method, eventType)) {
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            //将订阅方法信息添加到 findState 中
                            findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                    subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                        }
                    }
                } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                    String methodName = method.getDeclaringClass().getName()   "."   method.getName();
                    throw new EventBusException("@Subscribe method "   methodName  
                            "must have exactly 1 parameter but has "   parameterTypes.length);
                }
            } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                String methodName = method.getDeclaringClass().getName()   "."   method.getName();
                throw new EventBusException(methodName  
                        " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
            }
        }
    }

标题2:已经花销的平地风波还会有非常大大概重发吗?

开启stickyEvent。

公布事件的时候利用postSticky

EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!"));

而处理事件时,配置sticky = true。那样重启Activity的时候,先前的风云会重分发,省去了使用SharePreferences/Bundle保存情状的手续~

@Overridepublic void onStart() { super.onStart(); EventBus.getDefault().register;}@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)public void onEvent(MessageEvent event) { // UI updates must run on MainThread textField.setText(event.message);}@Overridepublic void onStop() { EventBus.getDefault().unregister; super.onStop();}

本来,当再也不必要以此sticky 伊夫nt时索要手动移除。

//移除sticky属性,然后将事件返回MessageEvent stickyEvent = EventBus.getDefault().removeStickyEvent(MessageEvent.class);// Better check that an event was actually posted beforeif(stickyEvent != null) { // Now do something with it}

可以的,使用注明参数priority轻便解决

@Subscribe(priority = 1); //默认的是0public void onEvent(MessageEvent event) {…}

能够的,使用cancelEventDelivery方法。高优先级的订阅者的特权啊!

// Called in the same thread @Subscribepublic void onEvent(MessageEvent event){// Process the event…EventBus.getDefault().cancelEventDelivery ;}
  1. EventBus Documentation:

订阅者索引相关##

在性质方面,EventBus 3由于应用了批注,比起利用反射来遍历方法的2.4本子逊色不菲。但开启索引后质量远远超过以前的版本。上面就来看一下对此伊夫ntBus的另一种选取办法。

在Project的build.gradle中增多正如代码:

buildscript {
    dependencies {
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}

接下来在app的build.gradle中增加正如代码:

apply plugin: 'com.neenbedankt.android-apt'

dependencies {
    compile 'org.greenrobot:eventbus:3.0.0'
    apt 'org.greenrobot:eventbus-annotation-processor:3.0.1'
}
apt {
    arguments {
        eventBusIndex "com.example.myapp.MyEventBusIndex"
    }
}

重新rebuild之后会在build目录下不熟稔成MyEventBusIndex文件,文件名能够自定义。下边就来看一下怎么使用那几个My伊夫ntBusIndex.大家可以自定义设置本人的EventBus来为其增加My伊夫ntBusIndex对象。代码如下所示:

EventBus eventBus = EventBus.builder().addIndex(new MyEventBusIndex()).build();

我们也能够将MyEventBusIndex对象设置在暗中认可的EventBus对象在那之中。代码如下所示:

EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
// Now the default instance uses the given index. Use it like this:
EventBus eventBus = EventBus.getDefault();

余下对于伊夫ntBus的用法规是一模二样。当然也建议通过丰富订阅者索引这种形式来利用EventBus,那样会比通过反射的方法来深入分析注解效能更加高。

前言

EventBus是一个Android开源库,其使用发布/订阅形式,以提供代码间的松耦合。EventBus使用中心通讯格局,仅仅使用几行简单的代码,就能够高达解耦代码的目标。从而,简化代码,移除信赖,加速应用软件的支付速度。

ca88编程 3

源代码地址:github


ASYN

将事件增添 cachedThreadPool 中实践(假如当前有空余线程,则复用空闲线程,若无就创办新线程State of Qatar

public void enqueue(Subscription subscription, Object event) {
    PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
    queue.enqueue(pendingPost);
    eventBus.getExecutorService().execute(this);//放到默认的 cachedThreaPool 中执行
}

@Override
public void run() {
    PendingPost pendingPost = queue.poll();
    if(pendingPost == null) {
        throw new IllegalStateException("No pending post available");
    }
    eventBus.invokeSubscriber(pendingPost);
}

并发背景

  • 七十十六线程景况下轻便产生回调鬼世界和那几个
  • Android中寄放的零部件间通讯格局丰富多彩(handler、intent、broadcast等等)

关于EventBus的思考##

不行使伊芙ntBus的前提下,在Android内部各种零件的互相通讯能够说是乱套,各个接口定义,注册、回调。搞得全部代码有着很要紧的耦合,接口中多多少个参数,参数类型改造都会引致众多地点要改。

观念的机件人机联作

这种思路决定了乘胜项目越发宏大,耦合会尤其的严重,所以一定必要一种新的笔触来清除这几个主题材料。

而伊芙ntBus的产出,很好的消除了那么些难点

EventBus

从这两幅图,大家可以清晰的感触到,伊夫ntBus给咱们代码全体的布局带给多么大的裨益,单从图上就足以看来明明减小了逐条零件之间的耦合;同期从代码角度出发,EventBus短短几行代码,就能够达成在此以前经过接口-注册接口-回调 等一多元的工作才干时不可失的专门的学问量。

当然,不论什么事要好自然有坏,伊夫ntBus使用方法的精练,也会引致大家在现身难点时无从入手,那就需求长日子的积攒经历了。然则简来说之,照旧利大于弊吧,所以当大家项目有雅量的平地风波交互作用时,EventBus不失为一种好的筛选!


如何使用(分3步)(怎么想起了大象放双门双门电冰箱...)

1.定义events,要是你须要越来越多的扩大性,能够寻思投入泛型:

    public class EventBusEvent {
        public final String info;
        public EventBusEvent (String Info) {
            this.info = Info;
        }
    }

2.准备 subscribers:
订阅者实现了事件管理方法,在事件被发送时,它将被调用。这一定于杰出观望者格局中的update(卡塔尔(قطر‎方法。在EventBus3.0中,在您的订阅方法上加多证明, 可以钦赐一个thread mode。並且,方法必得是public权限,其艺术参数有且只可以有叁个,此外类型必需为第一步定义好的事件类型:

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEvent(EventBusEvent eventBusEvent) {
        tv.setText(eventBusEvent.info);
    }

并且,register 和 unregister 你的 subscriber。仅仅当订阅者被注册后,它们技艺接受到事件。对于Android , activity 和 fragment 平常处境下应当依靠生命周期来register,抢先四分之二景色下,能够投身onStart/onStop中:

    @Override
    public void onStart() {
        super.onStart();
        EventBus.getDefault().register(this);
    }

    @Override
    public void onStop() {
        super.onStop();
        EventBus.getDefault().unregister(this);
    }

3.发送 events:
这一定于非凡观察者情势中的notifyObservers(卡塔尔方法。你可以在您的代码中的任哪个地方方发送事件,全体当前被登记的同一时间卓殊该事件类型的订阅者,都将收受到它。

    EventBus.getDefault().post(new EventBusEvent("Wild Android Monster"));

MAIN_ORDERED

新扩张的方式,然则最近版本的贯彻还不完备。

EventBus设计方式##

EventBus is an open-source library for Android using the publisher/subscriber pattern for loose coupling

那句话是greenrobot官方网址对EventBus的解释。

EventBus是三个针对Android为了松耦合的依靠事件公布/订阅方式(观望者情势)的开源库。

框架

从上航海用体育场地我们得以看到EventBus的规划构造非常轻松。

情状搭建

  • 不接受订阅者索引:

compile 'org.greenrobot:eventbus:3.0.0'

  • 使用订阅者索引:

某些复杂些,並且供给自然的认证,放在上边包车型地铁章节特意陈诉,在这里不再赘言。


一、概述

EventBus 是一个 Android 事件发布/订阅框架,通过解耦公布者和订阅者简化 Android 事件传递,这里的风云能够了然为新闻,本文中联合称为事件。事件传递既可用于 Android 四大组件间通信,也得以客商异步线程和主线程间通信等等。
历史观的风浪传递方式满含:Handler、BroadCastReceiver、Interface 回调,比较之下 EventBus 的长处是代码简洁,使用简易,并将事件公布和订阅丰硕解耦。

  • 事件(Event):又可称之为音讯,本文中集结用事件代表。其实正是二个目的,能够是互连网乞请重回的字符串,也能够是有个别开关状态等等。事件类型(EventType)指事件所属的 Class。
    • 事件分为日常事件和 Sticky 事件,相对于常常事件,Sticky 事件区别之处在于,当事件发布后,再有订阅者最早订阅该品种事件,依然能吸收接纳该类型事件这些年三个 Sticky 事件(所谓「如今一个」指的正是该项目事件「最后二遍产生」)。
  • 订阅者(Subscriber):订阅某种事件类型的对象。当有公布者公布那类事件后,伊夫ntBus 会实践订阅者的 on伊夫nt 函数,那一个函数叫事件响应函数。订阅者通过 register 接口订阅有些事件类型,unregister 接口退订。订阅者存在优先级,优先级高的订阅者能够收回事件后续向优先级低的订阅者分发,暗许全数订阅者优先级都为 0。
  • 发布者(Publisher):宣布某件事件的目的,通过 post 接口发表事件。

订阅者方法详细用法##

从以前对伊芙ntBus的德姆o大家得以见见,使用伊夫ntBus的首固然订阅者方法的落实,也正是事件管理方法onMessage伊芙nt的落到实处。那么些主意,才是我们管理数量、落成UI更新的器重。

 @Subscribe(threadMode = ThreadMode.POSTING,sticky = false,priority = 1)
    public void onMessageEvent(MessageEvent event) {
        tv.setText(event.message);
    }

此处再强调二次,这么些订阅者方法必须要增加@Subscribe那几个证明,那些评释的全部参数如上,前面是某些可选的参数。下边就相继参数做一下分析:

EventBus的ThreadMode总共有八种,何况都以在订阅者中的@Subscribe里展开制订的。上面就来看一下那多样ThreadMode。

方法一,运维期管理表明

在app 的 build.gradle 文件中丰盛注重

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

本文由ca88发布,转载请注明来源

关键词: ca88网址 Android 笔记 你可以 九阴真经