Android常用框架----事件总线系列框架

上篇介绍了json解析系列框架(http://blog.csdn.net/siwenyy/article/details/74999471),接下来新的系列又开始了,从场景介绍开始。

场景

你是否在开发的过程中遇到过想在ActivityB中回调ActivityA中的某个函数,但Activity又不能手动创建对象来设置一个Listener什么的? 你是否想在某个Service中想更新Activity或者Fragment中的界面? 

在实际项目开发中,经常会遇到当执行某个业务逻辑时,希望调用其他处理逻辑。
通常最简单粗暴的方法是直接依赖其他模块,调用模块相应方法,但这样会带来一些问题:
  • 模块间相互依赖,耦合度高。
  • 后期维护起来困难。
  • 代码缺少设计,不利于拓展。

Android中Activity、Service、Fragment之间的相互通信比较麻烦,主要有以下几种方式:

(1)使用广播,发送者发出广播,接收者接收广播后进行处理;

(2)使用Handler和Message,如下载线程完成下载任务后,给UI发送Message,UI收到Message后更新界面。


 以上两种比较繁琐,接下来给大家介绍一种比较简单有效的方法事件总线(定义:针对事件提供统一订阅,发布以达到组件间通信的解决方案。 原理:观察者模式。发送者把消息发送到事件总线,然后事件总线在接收者中查找哪些方法注册了这个事件,如果某个方法注册了这个事件,就触发该方法。事件总线框架提供了一种更灵活更强大而又更加完美解耦的解决方案,在很多场合,从开发效率,执行性能和设计思路上都要优于BroadcastReceiver


常用的事件总线框架

一、greenrobot的EventBus(官方参考:https://github.com/greenrobot/EventBus    最新版本 3.0.0

1.EventBus概述

EventBus的三要素

  • Event:事件,可以是任意类型的对象。
  • Subscriber:事件订阅者,在EventBus3.0之前消息处理的方法只能限定于onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,他们分别代表四种线程模型。而在EventBus3.0之后,事件处理的方法可以随便取名,但是需要添加一个注解@Subscribe,并且要指定线程模型(默认为POSTING)。
  • Publisher:事件发布者,可以在任意线程任意位置发送事件,直接调用EventBus的post(Object)方法。可以自己实例化。EventBus对象,但一般使用EventBus.getDefault()就好了,根据post函数参数的类型,会自动调用订阅相应类型事件的函数。

EventBus的四种ThreadMode(EventBus3.0

  • POSTING(默认):如果使用事件处理函数指定了线程模型为POSTING,那么该事件在哪个线程发布出来的,事件处理函数就会在这个线程中运行,也就是说发布事件和接收事件在同一个线程。在线程模型为POSTING的事件处理函数中尽量避免执行耗时操作,因为它会阻塞事件的传递,甚至有可能会引起ANR。
  • MAIN: 事件的处理会在UI线程中执行。事件处理时间不能太长,长了会ANR的。
  • BACKGROUND:如果事件是在UI线程中发布出来的,那么该事件处理函数就会在新的线程中运行,如果事件本来就是子线程中发布出来的,那么该事件处理函数直接在发布事件的线程中执行。在此事件处理函数中禁止进行UI更新操作。
  • ASYNC:无论事件在哪个线程发布,该事件处理函数都会在新建的子线程中执行,同样,此事件处理函数中禁止进行UI更新操作。

2.EventBus基本用法

EventBus使用起来很简单,分为以下五个步骤:

自定义一个事件类

在需要订阅事件的地方注册事件

发送事件

处理事件(前面说过,消息处理的方法可以随便取名,但是需要添加一个注解@Subscribe,并且要指定线程模型,默认为POSTING。

取消事件订阅


添加依赖库

android Studio 配置gradle:

       
       
       
       
compile 'org.greenrobot:eventbus:3.0.0'

定义消息事件类
         
         
         
         
package com.xiaolajiao.technologyset;
 
public class MessageEvent {
private String message;
public MessageEvent(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

注册和取消订阅事件
      
      
      
      
package com.xiaolajiao.technologyset;
 
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
 
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
public class MainActivity extends AppCompatActivity {
private TextView tv_message;
private Button bt_message,bt_subscription;
 
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_message = (TextView) this.findViewById(R.id.tv_message);
tv_message.setText("MainActivity");
bt_message=(Button)this.findViewById(R.id.bt_message);
bt_message.setText("跳转到SecondActivity");
bt_message.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, SecondActivity.class));
}
});
 
//注册事件
EventBus.getDefault().register(this);
}
 
@Override
protected void onDestroy() {
super.onDestroy();
//取消注册事件
EventBus.getDefault().unregister(this);
}
}

事件订阅者处理事件

这里我们的ThreadMode设置为MAIN,事件的处理会在UI线程中执行,用TextView来展示收到的事件消息

       
       
       
       
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMoonEvent(MessageEvent messageEvent){
tv_message.setText(messageEvent.getMessage());
}

事件发布者发布事件
       
       
       
       
package com.xiaolajiao.technologyset;
 
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
 
import org.greenrobot.eventbus.EventBus;
 
public class SecondActivity extends AppCompatActivity {
private Button bt_message;
private TextView tv_message,bt_subscription;
 
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_message = (TextView) this.findViewById(R.id.tv_message);
tv_message.setText("SecondActivity");
bt_message=(Button)this.findViewById(R.id.bt_message);
bt_message.setText("发送事件");
bt_message.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EventBus.getDefault().post(new MessageEvent("欢迎关注siwen的博客"));
finish();
}
});
 
}
}

3、EventBus3.0粘性事件就是在发送事件之后再订阅该事件也能收到该事件,跟黏性广播类似。

订阅粘性事件

在MainActivity中我们将注册事件添加到button的点击事件中:

       
       
       
       
bt_subscription.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//注册事件
EventBus.getDefault().register(MainActivity.this);
}
});

订阅者处理粘性事件

在MainActivity中新写一个方法用来处理粘性事件:

       
       
       
       
@Subscribe(threadMode = ThreadMode.POSTINGsticky = true)
public void ononMoonStickyEvent(MessageEvent messageEvent){
tv_message.setText(messageEvent.getMessage());
}

发送黏性事件

在SecondActivity中我们定义一个Button来发送粘性事件:

       
       
       
       
bt_subscription.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EventBus.getDefault().postSticky(new MessageEvent("粘性事件"));
finish();
}
});


运行效果,首先我们在MainActivity中并没有订阅事件,而是直接跳到SecondActivity中点击发送粘性事件按钮,这时界面回到MainActivity,我们看到TextView仍旧显示着MainActivity的字段,这是因为我们现在还没有订阅事件。

接下来我们点击订阅事件,TextView发生改变显示“粘性事件”。


4、ProGuard 混淆规则
       
       
       
       
-keepattributes *Annotation*
-keepclassmembers class ** {
@org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
 
# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
<init>(java.lang.Throwable);
}


参考资料 

快速Android开发系列通信篇之EventBus

Android EventBus框架(一)之使用详细介绍    

Android EventBus实战 没听过你就out了 

Android事件总线(一)EventBus3.0用法全解析 
Android事件总线(二)EventBus3.0源码解析 


二、Otto(官方参考:http://square.github.io/otto/    最新版本 1.3.8

是 Square公司发布的一个发布-订阅模式框架,它基于Google Guava 项目中的event bus模块开发,针对Android平台做了优化和加强。


基本用法

2.1 添加依赖库

android Studio 配置gradle:

       
       
       
       
compile 'com.squareup:otto:1.3.8'

2.2 定义消息类
        
        
        
        
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;
}
}

2.3 单例封装BUS
        
        
        
        
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;
}
}
otto的Bus类相当与EventBus中的EventBus类,它封装了otto的主要功能,但它不是个单例,每次都要用new创建出来,这样显然不是很方便,因此我们用单例模式将它封装起来。

2.4  注册和取消注册订阅事件
        
        
        
        
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);
}

otto同样需要注册和取消注册订阅事件,通过OttoBus得到Bus对象,调用Bus的register和unregister方法来注册和取消注册。


2.5 事件订阅者处理事件

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

和EventBus一样用@Subscribe来订阅事件,同样的用textView来显示接收到的消息。


2.6  使用post发送事件

        
        
        
        
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("siwen的博客更新了"));
finish();
}
});
}
}

2.7 使用@Produce来发布事件
         
         
         
         
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("siwen的博客更新了");
}
@Override
protected void onDestroy() {
super.onDestroy();
bus.unregister(this);
}
}
Produce注解用来生产发布事件,需要注意的是它生产事件前它需要注册,并且在生产完事件后需要取消注册。如果使用这种方法则在跳转到发布者所在的类中则会立即产生事件并触发订阅者。


资料参考
Android事件总线(三)otto用法全解析  
Android事件总线(四)源码解析otto

三、AndroidEventBus(官方参考:https://github.com/hehonghui/AndroidEventBus   最新版本1.0.5

类似于观察者模式,通过register函数将需要订阅事件的对象注册到事件总线中,然后根据@Subcriber注解来查找对象中的订阅方法,并且将这些订阅方法和订阅对象存储在map中。当用户在某个地方发布一个事件时,事件总线根据事件的参数类型和tag找到对应的订阅者对象,最后执行订阅者对象中的方法。这些订阅方法会执行在用户指定的线程模型中,比如mode=ThreadMode.ASYNC则表示该订阅方法执行在子线程中

AndroidEventBus的ThreadMode

它指定这个事件接收函数执行在哪个线程中,具体有如下三个选项:

  • ThreadMode.MAIN,事件接收函数执行在UI线程;
  • ThreadMode.POST,事件在哪个线程发布,接收函数就执行在哪个线程;
  • ThreadMode.ASYNC,事件执行在一个独立的异步线程中。

AndroidEventBus使用分为以下步骤:

将对象注册到AndroidEventBus中
使用@Subcriber标注订阅函数(只能有一个参数)
通过post函数发布事件

      
      
      
      
public class MainActivity extends Activity {
// 代码省略
@Subcriber(tag = "csuicide")
private void csuicideMyself(String msg) {
// do sth
finish();
}
@Subcriber(mode = ThreadMode.MAIN)
private void toastMsgFromEvent(String msg) {
// do sth
}
@Subcriber(tag = "async" mode = ThreadMode.ASYNC)
private void executeAsync(final String msg) {
// do sth
}
// 代码省略
}

     为MainActivity添加了以下三个订阅函数:

  • csuicideMyself:该订阅函数执行在主线程,接收事件的类型为String,tag为csuicide。当用户发布一个事件类型为String,且tag为csuicide的事件时将会触发该方法。
  • toastMsgFromEvent:该订阅函数也是执行在主线程,事件类型为String,且tag为默认。当用户发布一个事件类型为String,且tag为默认的事件时将会触发该方法。
  • executeAsync:该订阅函数也是执行在一个异步线程,事件类型为String,且tag为async。当用户发布一个事件类型为String,且tag为async的事件时将会触发该方法。 


现在头有点晕,具体使用请参考以下链接及官方文档
参考资料:Android事件总线 ( AndroidEventBus ) 框架发布    http://blog.csdn.net/zzy7075/article/details/43563215



总结:

1、Otto满足消息/事件传递的同时,也实现了组件间的解耦。跟EventBus一样,采用反射的方式对注册类中的所有方法进行扫描和调用(EventBus 3.0版本支持注解以及在编译期扫描事件订阅方法,性能上有较大提升)。 
2、Otto不同于EventBus的是,它使用注解的方式(@Subscribe、@Produce)来标注方法,EventBus必须定义以onEvent开头的几个方法,代码中语境比较突兀,且有可能会导致拼写错误。[EventBus 3.0支持注解方式,而且支持注解中设置ThreadMode、sticky事件、优先级]。 
3、Otto会将处理的线程跟发送的线程保持一致,你也可以自己设置线程,Bus提供了一个那样的参数。而EventBus则可以自己指定线程,有四种方式,可以在onEvent后面加个后缀。比如:onEventMainThread。
4、Android EventBus事件总线是一个Android平台轻量级的事件总线框架, 它简化了Activity、Fragment、Service等组件之间的交互,很大程度上降低了它们之间的耦合,使得代码更加简洁,耦合性更低,提升代码质量。
5、AndroidEventBus使用注解来标识接收函数,这样函数名不受限制。
6、 Otto只会查找当前类中的订阅者,跟Produce。但是EventBus会查找父类的订阅者。在post的时候,两个框架都会去查找Event的父类型,毕竟Event也是属于它的父类型类型。
7、EventBus和Otto都采用了很多缓存,比如查找订阅者的时候。事件与对应的订阅者也是缓存着的,都是使用了一种先解析将订阅者缓存起来,提高查找速度。
8、 用EventBus来处理网络请求太过简单粗暴,考虑使用Volley处理网络请求,volley支持请求缓存、请求队列和请求优先级,代码的结构清晰、扩展性强,很适合客户端轻小的请求。使用参考 Android常用的框架----网络框架
9、 EventBus中内置了并发处理机制,既支持工作线程向UI线程发送消息/事件,也支持从主线程发消息,工作线程来处理响应。


你可能感兴趣的:(android网络框架)