【澳门葡京备用网址】源码解析otto,Android事件总线

前言

上一篇小说中讲到了otto的用法,这一篇大家来讲一下otto的源码。大概有人以为otto过时了,不过透过源码大家上学的是高手设计otto时的设计意见,那种规划意见是可是时的。

前言

上一篇小说中讲到了otto的用法,这一篇我们来讲一下otto的源码。大概有人认为otto过时了,然则通过源码大家上学的是高手设计otto时的筹划意见,那种设计意见是然则时的。

前言

otto 是 Square公司颁发的一个公布-订阅情势框架,它依照谷歌 Guava
项目中的event
bus模块开发,针对Android平台做了优化和增长。即使Square已经终止了对otto的翻新并引进使用宝马7系xJava和TiggoxAndroid来代替它,但是otto的布署理念和源码照旧值得学习,这一篇先来读书下otto的应用格局。

前两日在万众号里发了一篇有关伊夫ntBus的文章《玩转伊夫ntBus,详解其使用》,有读者和开发者反馈说并未OTTO好用。确实是,各有优缺点吧,那明天就有必不可少再讲一下奥托事件框架。

otto各样类的功力

率先先来看一下otto的源码的顺序类的效应,如下图所示。
澳门葡京备用网址 1

如图所示,otto的源码并不多,首要的类的法力如下:

  • Produce、Subscribe:发表者和订阅者注明类。
  • Bus:事件总线类,用来注册和取消注册,维护公布-订阅模型,并处负责人件调度分发。
  • HandlerFinder、AnnotatedHandlerFinder:用来探寻发表者和订阅者。
  • 伊夫ntProducer、伊芙ntHandler:分别封装发表者和订阅者的数据结构。

otto种种类的法力

首先先来看一下otto的源码的次第类的功能,如下图所示。

如图所示,otto的源码并不多,紧要的类的功用如下:

  • Produce、Subscribe:发布者和订阅者声明类。
  • Bus:事件总线类,用来注册和注销注册,维护揭橥-订阅模型,并处管事人件调度分发。
  • HandlerFinder、AnnotatedHandlerFinder:用来寻觅公布者和订阅者。
  • 伊夫ntProducer、伊芙ntHandler:分别封装发表者和订阅者的数据结构。

添加看重库

首先配置gradle,如下所示。

compile 'com.squareup:otto:1.3.8'

OTTO是Square推出的根据Guava项目的Android接济库,otto是3个轩然大波总线,用于应用程序的分化组件之间举办中用的通讯。OTTO是基于Observer的设计情势。它有宣布者,订阅者那七个第②对象。OTTO的极品实践就是由此反射就义了细微的质量,同时极大的下挫了先后的耦合度。

otto构造函数

在动用otto时,首先要创建Bus类,Bus类的构造函数如下所示。

澳门葡京备用网址 2澳门葡京备用网址 3

public Bus() {
    this(DEFAULT_IDENTIFIER);
}

View Code

这个DEFAULT_IDENTIFIERAV4是八个字符串”default”,this调用了Bus类的另二个构造函数:

澳门葡京备用网址 4澳门葡京备用网址 5

public Bus(String identifier) {
   this(ThreadEnforcer.MAIN, identifier);
 }

View Code

ThreadEnforcer.MAIN意味着暗许在主线程中调度事件,再往里看this又调用了什么样,如下所示。

澳门葡京备用网址 6澳门葡京备用网址 7

public Bus(ThreadEnforcer enforcer, String identifier) {
  this(enforcer, identifier, HandlerFinder.ANNOTATED);
}

View Code

率先个参数大家关系了,就是事件调度的简称,identifier为Bus的称号,专断认同为”default”。而identifier则是HandlerFinder,用于在register、unregister的时候寻找具有的subscriber和producer。再往里查看this又调用了怎么,如下所示。

澳门葡京备用网址 8澳门葡京备用网址 9

Bus(ThreadEnforcer enforcer, String identifier, HandlerFinder handlerFinder) {
  this.enforcer =  enforcer;
  this.identifier = identifier;
  this.handlerFinder = handlerFinder;
}

View Code

以此是终极调用的Bus的构造函数,在那里要首先记住handlerFinder
指的就是传进来的HandlerFinder.ANNOTATED,前面在注册时会用到handlerFinder那几个性子。

【澳门葡京备用网址】源码解析otto,Android事件总线。otto构造函数

在选拔otto时,首先要创造Bus类,Bus类的构造函数如下所示。

public Bus() {
    this(DEFAULT_IDENTIFIER);
  }

这个DEFAULT_IDENTIFIE昂科拉是五个字符串”default”,this调用了Bus类的另三个构造函数:

 public Bus(String identifier) {
    this(ThreadEnforcer.MAIN, identifier);
  }

ThreadEnforcer.MAIN意味着私行认同在主线程中调度事件,再往里看this又调用了何等,如下所示。

  public Bus(ThreadEnforcer enforcer, String identifier) {
    this(enforcer, identifier, HandlerFinder.ANNOTATED);
  }

率先个参数我们关系了,就是事件调度的简称,identifier为Bus的称谓,默许为”default”。而identifier则是HandlerFinder,用于在register、unregister的时候寻找具有的subscriber和producer。再往里查看this又调用了哪些,如下所示。

  Bus(ThreadEnforcer enforcer, String identifier, HandlerFinder handlerFinder) {
    this.enforcer =  enforcer;
    this.identifier = identifier;
    this.handlerFinder = handlerFinder;
  }

本条是最后调用的Bus的构造函数,在此间要首先记住handlerFinder
指的就是传进来的HandlerFinder.ANNOTATED,前面在登记时会用到handlerFinder这么些天性。

概念新闻类

与伊夫ntBus一样,我们跟着定义消息类,它是三个bean文件,如下所示。

public class BusData {
    public String message;
    public BusData(String message){
        this.message=message;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
}

Otto 官网:
http://square.github.io/otto/

注册

生成bus类后,大家要调用它的register方法来进行挂号。register方法如下所示。

澳门葡京备用网址 10澳门葡京备用网址 11

public void register(Object object) {
    if (object == null) {
      throw new NullPointerException("Object to register must not be null.");
    }
    enforcer.enforce(this);
    Map<Class<?>, EventProducer> foundProducers = handlerFinder.findAllProducers(object);//1
...
}

View Code

注明1出调用了handlerFinder的findAllProducers方法,从前讲到构造函数时,大家了然那一个handlerFinder指的是HandlerFinder.ANNOTATED,ANNOTATED的代码如下所示。

澳门葡京备用网址 12澳门葡京备用网址 13

HandlerFinder ANNOTATED = new HandlerFinder() {
   @Override
   public Map<Class<?>, EventProducer> findAllProducers(Object listener) {
     return AnnotatedHandlerFinder.findAllProducers(listener);
   }
   @Override
   public Map<Class<?>, Set<EventHandler>> findAllSubscribers(Object listener) {
     return AnnotatedHandlerFinder.findAllSubscribers(listener);
   }
 };

View Code

从上面的代码的findAllProducers方法和findAllSubscribers方法的重回值可以估算出二个注册类只好有3个发表者,却可以有五个订阅者。findAllProducers方法最后调用的是AnnotatedHandlerFinder的findAllProducers方法:

澳门葡京备用网址 14澳门葡京备用网址 15

static Map<Class<?>, EventProducer> findAllProducers(Object listener) {
  final Class<?> listenerClass = listener.getClass();
  Map<Class<?>, EventProducer> handlersInMethod = new HashMap<Class<?>, EventProducer>();
  Map<Class<?>, Method> methods = PRODUCERS_CACHE.get(listenerClass);//1
  if (null == methods) {
    methods = new HashMap<Class<?>, Method>();
    loadAnnotatedProducerMethods(listenerClass, methods);//2
  }
  if (!methods.isEmpty()) {
    for (Map.Entry<Class<?>, Method> e : methods.entrySet()) {//3
      EventProducer producer = new EventProducer(listener, e.getValue());
      handlersInMethod.put(e.getKey(), producer);
    }
  }
  return handlersInMethod;
}

View Code

PRODUCERS_CACHE是五个ConcurrentHashMap,它的key为bus.register()时传出的class,而value是贰个map,这些map的key是事件的class,value是生育事件的法门。注释1处首先在PRODUCE库罗德S_CACHE依据传入的靶子的档次查找是还是不是有缓存的风浪措施,如若没有就调用注释2处的代码应用反射去搜寻具有应用了@Produce评释的点子,并且将结果缓存到PRODUCE奥迪Q7S_CACHE中。接着在诠释3处遍历这一个事件措施,并为各种事件措施制造了伊芙ntProducer类,并将那几个伊芙ntProducer类作为value存入handlersInMethod并回到。接下来我们再次回到register方法。如下所示。

澳门葡京备用网址 16澳门葡京备用网址 17

public void register(Object object) {
  if (object == null) {
    throw new NullPointerException("Object to register must not be null.");
  }
  enforcer.enforce(this);
  Map<Class<?>, EventProducer> foundProducers = handlerFinder.findAllProducers(object);
  for (Class<?> type : foundProducers.keySet()) {
    final EventProducer producer = foundProducers.get(type);
    EventProducer previousProducer = producersByType.putIfAbsent(type, producer);//1
    if (previousProducer != null) {
      throw new IllegalArgumentException("Producer method for type " + type
        + " found on type " + producer.target.getClass()
        + ", but already registered by type " + previousProducer.target.getClass() + ".");
    }
    Set<EventHandler> handlers = handlersByType.get(type);
    if (handlers != null && !handlers.isEmpty()) {
      for (EventHandler handler : handlers) {
        dispatchProducerResultToHandler(handler, producer);//2
      }
    }
  }
  ...
}

View Code

调用完findAllProducers方法后,会在诠释1处检讨是还是不是有该项目标发表者已经存在,如果存在则抛出格外,不存在则调用注释2处的dispatchProducerResultToHandler方法来触发和公布者对应的订阅者来处管事人件。接下来register方法的后一片段代码就不帖上来了,跟原先的流程大概相同就是调用findAllSubscribers方法来搜寻全数应用了@Subscribe评释的措施,跟以前区其余是3个注册类可以有多个订阅者,接下去判断是还是不是有该品种的订阅者存在,约等于判定注册类是或不是曾经登记,借使存在则抛出特别,不设有则查找是或不是有和这么些订阅者对应的公布者,假设有的话,就会触发对应的订阅者处总管件。

注册

生成bus类后,我们要调用它的register方法来进展挂号。register方法如下所示。

public void register(Object object) {
    if (object == null) {
      throw new NullPointerException("Object to register must not be null.");
    }
    enforcer.enforce(this);
    Map<Class<?>, EventProducer> foundProducers = handlerFinder.findAllProducers(object);//1
...
}

讲明1出调用了handlerFinder的findAllProducers方法,在此以前讲到构造函数时,我们明白那一个handlerFinder指的是HandlerFinder.ANNOTATED,ANNOTATED的代码如下所示。

 HandlerFinder ANNOTATED = new HandlerFinder() {
    @Override
    public Map<Class<?>, EventProducer> findAllProducers(Object listener) {
      return AnnotatedHandlerFinder.findAllProducers(listener);
    }
    @Override
    public Map<Class<?>, Set<EventHandler>> findAllSubscribers(Object listener) {
      return AnnotatedHandlerFinder.findAllSubscribers(listener);
    }
  };

从上边的代码的findAllProducers方法和findAllSubscribers方法的再次回到值可以推论出壹个注册类只可以有三个发表者,却可以有多少个订阅者。findAllProducers方法最后调用的是AnnotatedHandlerFinder的findAllProducers方法:

  static Map<Class<?>, EventProducer> findAllProducers(Object listener) {
    final Class<?> listenerClass = listener.getClass();
    Map<Class<?>, EventProducer> handlersInMethod = new HashMap<Class<?>, EventProducer>();
    Map<Class<?>, Method> methods = PRODUCERS_CACHE.get(listenerClass);//1
    if (null == methods) {
      methods = new HashMap<Class<?>, Method>();
      loadAnnotatedProducerMethods(listenerClass, methods);//2
    }
    if (!methods.isEmpty()) {
      for (Map.Entry<Class<?>, Method> e : methods.entrySet()) {//3
        EventProducer producer = new EventProducer(listener, e.getValue());
        handlersInMethod.put(e.getKey(), producer);
      }
    }
    return handlersInMethod;
  }

PRODUCERS_CACHE是2个ConcurrentHashMap,它的key为bus.register()时传出的class,而value是三个map,这么些map的key是事件的class,value是生育事件的法子。注释1处首先在PRODUCE奥迪Q3S_CACHE依照传入的对象的种类查找是不是有缓存的风浪措施,借使没有就调用注释2处的代码应用反射去寻找具有应用了@Produce注脚的方式,并且将结果缓存到PRODUCE讴歌RDXS_CACHE中。接着在诠释3处遍历这一个事件措施,并为逐个事件措施成立了伊芙ntProducer类,并将那些伊芙ntProducer类作为value存入handlersInMethod并重临。接下来咱们回来register方法。如下所示。

  public void register(Object object) {
    if (object == null) {
      throw new NullPointerException("Object to register must not be null.");
    }
    enforcer.enforce(this);
    Map<Class<?>, EventProducer> foundProducers = handlerFinder.findAllProducers(object);
    for (Class<?> type : foundProducers.keySet()) {
      final EventProducer producer = foundProducers.get(type);
      EventProducer previousProducer = producersByType.putIfAbsent(type, producer);//1
      if (previousProducer != null) {
        throw new IllegalArgumentException("Producer method for type " + type
          + " found on type " + producer.target.getClass()
          + ", but already registered by type " + previousProducer.target.getClass() + ".");
      }
      Set<EventHandler> handlers = handlersByType.get(type);
      if (handlers != null && !handlers.isEmpty()) {
        for (EventHandler handler : handlers) {
          dispatchProducerResultToHandler(handler, producer);//2
        }
      }
    }
    ...
  }

调用完findAllProducers方法后,会在诠释1处检讨是或不是有该品种的公布者已经存在,即使存在则抛出格外,不设有则调用注释2处的dispatchProducerResultToHandler方法来触发和发表者对应的订阅者来处总管件。接下来register方法的后一有的代码就不帖上来了,跟从前的流水线大概相同就是调用findAllSubscribers方法来探寻所有应用了@Subscribe注解的点子,跟以前不等的是二个注册类可以有多少个订阅者,接下去判断是不是有该品种的订阅者存在,也等于判定注册类是否曾经登记,如果存在则抛出十二分,不设有则查找是还是不是有和那么些订阅者对应的发表者,借使有的话,就会触发对应的订阅者处管事人件。

单例封装Bus

otto的Bus类万分与伊夫ntBus中的伊夫ntBus类,它包裹了otto的根本功用,但它不是个单例,每一趟都要用new成立出来,那样让人惊讶不是很有利,因而大家用单例方式将它包裹起来,如下所示。

public class OttoBus extends Bus{
    private volatile static OttoBus bus;
    private OttoBus (){
    }
    public static OttoBus getInstance() {
        if (bus == null) {
            synchronized (OttoBus.class){
             if(bus==null){
                 bus = new OttoBus();
             }
            }
        }
        return bus;
    }
}

Why和行使场景

出殡事件

大家会调用Bus的post方法来发送事件,它的代码如下所示。

澳门葡京备用网址 18澳门葡京备用网址 19

public void post(Object event) {
  if (event == null) {
    throw new NullPointerException("Event to post must not be null.");
  }
  enforcer.enforce(this);
  Set<Class<?>> dispatchTypes = flattenHierarchy(event.getClass());//1
  boolean dispatched = false;
  for (Class<?> eventType : dispatchTypes) {
    Set<EventHandler> wrappers = getHandlersForEventType(eventType);
    if (wrappers != null && !wrappers.isEmpty()) {
      dispatched = true;
      for (EventHandler wrapper : wrappers) {
        enqueueEvent(event, wrapper);//2
      }
    }
  }
  if (!dispatched && !(event instanceof DeadEvent)) {
    post(new DeadEvent(this, event));
  }
  dispatchQueuedEvents();//3
}

View Code

声明1处的flattenHierarchy方法首先会从缓存中搜索传进来的event(音信事件类)的富有父类,假如没有则找到event的具备父类并蕴藏入缓存中。接下来遍历那些父类找到它们的有所订阅者,并在诠释2处将那么些订阅者压入线程的事件队列中。并在诠释3处调用dispatchQueued伊夫nts方法依次取出事件队列中的订阅者来拍卖相应event的轩然大波。

出殡事件

大家会调用Bus的post方法来发送事件,它的代码如下所示。

  public void post(Object event) {
    if (event == null) {
      throw new NullPointerException("Event to post must not be null.");
    }
    enforcer.enforce(this);
    Set<Class<?>> dispatchTypes = flattenHierarchy(event.getClass());//1
    boolean dispatched = false;
    for (Class<?> eventType : dispatchTypes) {
      Set<EventHandler> wrappers = getHandlersForEventType(eventType);
      if (wrappers != null && !wrappers.isEmpty()) {
        dispatched = true;
        for (EventHandler wrapper : wrappers) {
          enqueueEvent(event, wrapper);//2
        }
      }
    }
    if (!dispatched && !(event instanceof DeadEvent)) {
      post(new DeadEvent(this, event));
    }
    dispatchQueuedEvents();//3
  }

注脚1处的flattenHierarchy方法首先会从缓存中搜寻传进来的event(音讯事件类)的全数父类,如若没有则找到event的富有父类并蕴藏入缓存中。接下来遍历这么些父类找到它们的持有订阅者,并在诠释2处将这一个订阅者压入线程的事件队列中。并在诠释3处调用dispatchQueued伊芙nts方法依次取出事件队列中的订阅者来处理相应event的事件。

挂号和撤消注册订阅事件

otto同样须求登记和撤回注册订阅事件,通过奥托Bus得到Bus对象,调用Bus的register和unregister方法来注册和打消注册,同时我们定义八个button,点击那几个button跳转到SecondActivity,SecondActivity用来发送事件。代码如下所示。

public class MainActivity extends AppCompatActivity {
    private Button bt_jump;
    private TextView tv_message;
    private Bus bus;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_message= (TextView) this.findViewById(R.id.tv_message);
        bt_jump= (Button) this.findViewById(R.id.bt_jump);
        bt_jump.setText("跳转到SecondActivity");
        bt_jump.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this,SecondActivity.class));
            }
        });
        bus=OttoBus.getInstance();
        bus.register(this);
    }

 @Override
    protected void onDestroy() {
        super.onDestroy();
         //取消注册订阅事件
        bus.unregister(this);
    }

1. Why

Otto框架的基本点功效是资助咱们来下滑两个零件通讯之间的耦合度的(解耦)。

撤回注册

打消注册时,我们会调用Bus的unregister方法,unregister方法如下所示。

澳门葡京备用网址 20澳门葡京备用网址 21

public void unregister(Object object) {
  if (object == null) {
    throw new NullPointerException("Object to unregister must not be null.");
  }
  enforcer.enforce(this);
  Map<Class<?>, EventProducer> producersInListener = handlerFinder.findAllProducers(object);//1
  for (Map.Entry<Class<?>, EventProducer> entry : producersInListener.entrySet()) {
    final Class<?> key = entry.getKey();
    EventProducer producer = getProducerForEventType(key);
    EventProducer value = entry.getValue();
    if (value == null || !value.equals(producer)) {
      throw new IllegalArgumentException(
          "Missing event producer for an annotated method. Is " + object.getClass()
              + " registered?");
    }
    producersByType.remove(key).invalidate();//2
  }
...
}

View Code

注销注册分为两片段,一部分是订阅者打消注册,另一某个是公布者废除注册。那两有的的代码类似,由此,上边的代码只列出了发表者取消注册的代码。在诠释1处得到全部应用@Produce声明的形式,并遍历那一个措施,调用注释2处的代码从缓存中清除全数和传进来的注册类相关的发表者,来成功公布者的废除注册操作。

打消注册

注销注册时,大家会调用Bus的unregister方法,unregister方法如下所示。

  public void unregister(Object object) {
    if (object == null) {
      throw new NullPointerException("Object to unregister must not be null.");
    }
    enforcer.enforce(this);
    Map<Class<?>, EventProducer> producersInListener = handlerFinder.findAllProducers(object);//1
    for (Map.Entry<Class<?>, EventProducer> entry : producersInListener.entrySet()) {
      final Class<?> key = entry.getKey();
      EventProducer producer = getProducerForEventType(key);
      EventProducer value = entry.getValue();
      if (value == null || !value.equals(producer)) {
        throw new IllegalArgumentException(
            "Missing event producer for an annotated method. Is " + object.getClass()
                + " registered?");
      }
      producersByType.remove(key).invalidate();//2
    }
  ...
  }

撤废注册分为两部分,一部分是订阅者打消注册,另一有的是发表者撤除注册。那两局地的代码类似,因而,上面的代码只列出了宣布者废除注册的代码。在诠释1处拿到全体应用@Produce注明的艺术,并遍历这一个办法,调用注释2处的代码从缓存中化解全部和传进来的注册类相关的发表者,来形成公布者的取消注册操作。

事件订阅者处总管件

和伊夫ntBus一样用@Subscribe来订阅事件,在MainActivity中添加如下代码。

  @Subscribe
    public void setContent(BusData data) {
        tv_message.setText(data.getMessage());
    }

同一的用textView来突显接收到的新闻。

行使post发送事件
创建SecondActivity,并安装三个button,点击发送事件,并finish掉自己,如下所示。

public class SecondActivity extends AppCompatActivity {
    private Button bt_jump;
    private OttoBus bus;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bt_jump= (Button) this.findViewById(R.id.bt_jump);
        bt_jump.setText("发送事件");
        bt_jump.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                OttoBus.getInstance().post(new BusData("刘望舒的博客更新了"));
                finish();
            }
        });
    }
}

这么大家运转程序点击MainActivity的”跳转到SecondActivity”按钮直接跳转到SecondActivity,再点击”发送事件”按钮,SecondActivity被finish掉回到MainActivity
,MainActivity 中的textView的文字变为了”刘望舒的博客更新了”。

2. 施用场景

譬如说:由界面 A 跳转到界面 B ,然后点击 B 中的 button, 未来要翻新 界面 A
的视图。再譬如:界面有1个 界面 A,A 里面的有个 Fragment, 点击 Fragment
中的3个 button,跳转到界面 B, 点击界面 B的 button 要更新界面 A 的
Fragment 的视图,等等。

作者们能够见见地点举例的三种情景,在此之前可以用startActivityForResult 和
interface
的点子落成的话,会相比劳顿,并且产生了无数的动静判断和逻辑判断,并且只怕爆发众多不须要的
bug, 代码量也比较大和麻烦,使用 otto 就足以能便于的幸免那些题材。

行使@Produce来公布事件

Produce阐明用来生产发表事件,须求专注的是它生产事件前它要求登记,并且在生养完事件后必要撤消注册。如若使用那种办法则在跳转到发表者所在的类中则会立马发生事件并触发订阅者,修改SecondActivity,代码如下所示。

public class SecondActivity extends AppCompatActivity {
    private Button bt_jump;
    private OttoBus bus;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bt_jump= (Button) this.findViewById(R.id.bt_jump);
        bt_jump.setText("发送事件");
        bt_jump.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {               
                finish();
            }
        });
        bus=OttoBus.getInstance();
        bus.register(this);
    }
    @Produce
    public BusData setInitialContent() {
        return new BusData("刘望舒的博客更新了");
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        bus.unregister(this);
    }
}

在MainActivity跳转到SecondActivity时,MainActivity会立刻收到事件。

github源码下载

主导用法

引入Otto

dependencies {
  compile 'com.squareup:otto:1.3.8'
}

概念事件:

public class MessageEvent { /* Additional fields if needed */ }

澳门葡京备用网址 ,订阅和撤废订阅

bus.register(this);

bus.unregister(this);

发布:

bus.post(new MessageEvent());

注解

@Subscribe:这些在调用了register后有效,表示订阅了一个事变,并且方法的用
public 修饰的.方法名可以随意取,重点是参数,它是按照你的参数进行判断

@Produce评释告诉Bus该函数是三个轩然大波时有爆发者,发生的轩然大波类型为该函数的重回值。

末段,proguard 必要做一些万分处理,幸免混淆:

-keepattributes *Annotation*
-keepclassmembers class ** {
    @com.squareup.otto.Subscribe public *;
    @com.squareup.otto.Produce public *;
}

骨子里例子

首先完毕一个Bus的单例

package com.loonggg.ottodemo;

import com.squareup.otto.Bus;

public final class BusProvider {
    private static final Bus BUS = new Bus();

    public static Bus getInstance() {
        return BUS;
    }

    private BusProvider() {
    }
}

说不上是自定义1个定义伊夫nt事件,用来封装信息

package com.loonggg.ottodemo;

public class MessageEvent {
    public String msg;

    public MessageEvent(String msg) {
        this.msg = msg;
    }
}

双重是MainActivity,订阅事件

public class MainActivity extends Activity {
    private Button btn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        BusProvider.getInstance().register(this);
        btn = (Button) findViewById(R.id.btn_two);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(SecondActivity.this, ThreeActivity.class));
            }
        });

    }
    //这个注解一定要有,表示订阅了MessageEvent,并且方法的用 public 修饰的.方法名可以随意取,重点是参数,它是根据你的参数进行判断来自于哪个发送的事件
    @Subscribe
    public void showEvent(MessageEvent event) {
        btn.setText(event.msg);
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        BusProvider.getInstance().unregister(this);
    }
}

说到底事发送订阅事件

public class ThreeActivity extends Activity {
    private Button btn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_three);
        btn = (Button) findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                BusProvider.getInstance().post(produceMessageEvent());
                //或者这样用也行
                //BusProvider.getInstance().post(new MessageEvent("非著名程序员"));
                finish();
            }
        });

    }

    @Produce
    public MessageEvent produceMessageEvent() {
        return new MessageEvent("非著名程序员");
    }

//    @Override
//    protected void onResume() {
//        super.onResume();
//        BusProvider.getInstance().register(this);
//    }
//
//    @Override
//    protected void onPause() {
//        super.onPause();
//        BusProvider.getInstance().unregister(this);
//    }
}

总结

由此例子大家能够发现,其实事件揭橥者不用@Produce注明和挂号事件也可以发布新闻。可是你要Subscribe订阅事件就必然要register那几个类了,否则是经受不到事件的。

与EventBus的对比

从事件订阅的拍卖差异来看:

① 、eventbus是采用反射的办法对全体注册的类的享有办法开展扫描来形成登记;

贰 、otto选拔了诠释的章程成功注册;

叁 、共同的地点缓存全部注册并有可用性的检测。同时可以移除注册;

四 、注册的共同点都以行使method方法开展一个并入。

在otto越来越多采用境况应该就是在主线程中,因为它其中从不异步线程的现象。(只怕是它自个儿的固化不平等,它就是为了消除UI的通信机制。所以出发点就是轻量级)在代码中任重(英文名:rèn zhòng)而道远反映这一表征的地点就是在接口ThreadEnforcer以及其中的贯彻域ANY和MAIN。在MAIN内部有2个是不是是主线程的检讨,而ANY不做任何检查的作业。

伊芙ntBus在3.0原先,还索要根据各样线程方式分别对应固定接收形式,而OTTO则可以透过声明的措施自定义方法,相比便宜,不过伊夫ntBus在3.0也已毕了通过注脚自定义方法了。而otto介绍上随便是订阅者仍然发送者都急需登记事件,不过作者意识将来发送者不用登记也可以发送了。

每一种框架都有友好的特点,大家开发者必须领悟逐个框架的观点才能更好的施用,没有哪个框架好不佳的题材,只要开发者自身使用哪个舒服,哪个就是最好的。适合自身的才是最好的。

末段本身想说,只怕伊芙ntBus和奥托很早在此在此以前就有了,今后奇骏xJava就能已毕那样的效用,不过对于不断解Lacrossex技术的人的话,那么些还是要命有效的,QX56x技术虽好,就算很新,倘若没有搞懂的景观下,贸然使用估量会给您带来很大的难堪。最幸好有二个相比懂Escortx技术的人的前提下,开始运用,升高协调。

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website