Android EventBus3.0实例使用详解及封装调用

来源:互联网 发布:凯文淘宝店 编辑:程序博客网 时间:2024/06/05 06:22

EventBus是一款Android下的发布/订阅事件总线机制。可以代替Intent、Handler、Broadcast等在Fragment、Activity之间传递消息。

优点:开销小,代码优雅。将发送者和接受者解耦。

3.0与2.x的区别

主要区别在订阅函数的不同

EventBus2.x中只暴露了四个方法供用户调用,分别是

  • onEvent:该事件在哪个线程发布出来的,onEvent就会在这个线程中运行,也就是说发布事件和接收事件线程在同一个线程。使用这个方法时,在onEvent方法中不能执行耗时操作,如果执行耗时操作容易导致事件分发延迟。
  • onEventMainThread:不论事件是在哪个线程中发布出来的,onEventMainThread都会在UI线程中执行,接收事件就会在UI线程中运行,这个在Android中是非常有用的,因为在Android中只能在UI线程中跟新UI,所以在onEvnetMainThread方法中是不能执行耗时操作的。
  • onEventBackgroundThread:如果事件是在UI线程中发布出来的,那么onEventBackground就会在子线程中运行,如果事件本来就是子线程中发布出来的,那么onEventBackground函数直接在该子线程中执行。
  • onEventAsync:无论事件在哪个线程发布,都会创建新的子线程在执行onEventAsync.

EventBus3.0中必须使用注解,例如:

@Subscribe(threadMode = ThreadMode.Async, sticky = true, priority = 1)public void firstEvent(FirstEvent event) {    Log.e("TAG", "Async" + Thread.currentThread().getName());}

好处在于订阅函数可以随便起名字,其他与2.x没什么不同。<br/>这里Subscribe中的key需要解释一下含义,Subscribe中可以传三种值:

  • ThreadMode:这是个枚举,有四个值,决定订阅函数在哪个线程执行

    • PostThread:事件发送者在哪个线程就执行在哪个线程。同2.x中的onEvent方法,默认值就是这个
    • MainThread:订阅函数一定执行在主线程。同onEventMainThread方法
    • BackgroundThread:如果是事件从子线程发出,订阅函数就执行在那个子线程,不会创建新的子线程;如果主线程发出事件,则创建子线程。同onEventBackgroundThread方法
    • Async:一定创建子线程。同onEventAsync方法。
  • sticky:默认为false,如果为true,当通过postSticky发送一个事件时,这个类型的事件的最后一次事件会被缓存起来,当有订阅者注册时,会把之前缓存起来的这个事件直接发送给它。使用在比如事件发送者先启动了,订阅者还没启动的情况。

  • priority:默认值为0。订阅了同一个事件的订阅函数,在ThreadMode值相同的前提下,收到事件的优先级。

Configuration用法:

当默认的EventBus不足以满足需求时,EventBusBuilder就上场了,EventBusBuilder允许配置各种需求的EventBus

例如1:当没有subscribers的时候,eventbus保持静默:EventBus eventBus = EventBus.builder().logNoSubscriberMessages(false)    .sendNoSubscriberEvent(false).build();例如2:配置异常:默认情况下:eventbus捕获onevent抛出的异常,并且发送一个SubscriberExceptionEvent 可能不必处理EventBus eventBus = EventBus.builder().throwSubscriberException(true).build();

配置默认的eventbus单例

官方推荐:在application类中,配置eventbus单例,保证eventbus的统一

例如:配置eventbus 只在DEBUG模式下,抛出异常,便于自测,同时又不会导致release环境的app崩溃EventBus.builder().throwSubscriberException(BuildConfig.DEBUG).installDefaultEventBus();

Sticky Events用法:

前面说的一般的post event,正常流程,必须是先register,然后post event,handle event才能起作用。但是当我们post event时,还没有subcriber怎么办?但是又想后注册的subscriber,能收到消息,这时sticky event就开始大显身手了。

Warning:EventBus会把最后一个sticky event记录在内存中,然后分发给subscriber

来看下官方的Demo

1 post sticky event:EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!"));2 启动一个新的Activity,准备subscriber,注册后,所有的sticky subscriber的回调方法,会马上获得之前的sticky event@Overridepublic void onStart() {    super.onStart();    EventBus.getDefault().register(this);}//注意这里sticky=true@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(this);    super.onStop();}

Getting and Removing sticky Events manually

如上所述,当subscriber注册后,最后一个sticky event会自动匹配。但是,有些时候,主动去检查sticky event会更方便,并且 sticky event 需要remove,阻断继续传递。

官方demo

//返回的是之前的sticky eventMessageEvent stickyEvent = EventBus.getDefault().removeStickyEvent(MessageEvent.class);// Better check that an event was actually posted beforeif(stickyEvent != null) {    // Now do something with it}

2中sticky event使用方法都可行,看业务需要和个人习惯,选择合适的使用方法

Priorities and Event Cancellation用法:

大多数情况下,eventbus不需要改变线程优先级,或者取消event,但是不排除少数情况,需要改变线程优先级。

Subscriber Priorities

官方demo

//priority默认为0,不同ThreadMode下的分发流程不受优先级的影响//优先级高的可以优先获得消息@Subscribe(priority = 1);public void onEvent(MessageEvent event) {…}

Cancelling event delivery

如果,不希望后续的subcriber收到消息,可以在收到消息后,调用cancelEventDelivery(Object event) 取消消息的后续传递。

官方demo

@Subscribepublic void onEvent(MessageEvent event){// Process the event…EventBus.getDefault().cancelEventDelivery(event) ;}

Note:一般情况下,event的取消发生在高优先级的subscriber


具体使用

创建事件:

public class FirstEvent {    private String msg;    public FirstEvent(String msg){        this.msg = msg;    }    public String getMsg(){        return msg;    }}

使用场景一:在Activity之间通信传值

在MainActivity的onCreate方法中注册,onDestroy方法中反注册

EventBus.getDefault().register(this);EventBus.getDefault().unregister(this);

订阅函数,此处用来查看执行在哪个线程(注意,这里的函数名可以任取):

@Subscribe(threadMode = ThreadMode.Async, sticky = true, priority = 1)public void onAsync(FirstEvent event) {    Log.e("TAG", "Async: " + Thread.currentThread().getName());}@Subscribe(threadMode = ThreadMode.BackgroundThread)public void onBackgroundThread(FirstEvent event) {    Log.e("TAG", "BackgroundThread: " + Thread.currentThread().getName());}@Subscribe(threadMode = ThreadMode.MainThread)public void onMainThread(FirstEvent event) {    Log.e("TAG", "MainThread: " + Thread.currentThread().getName());}@Subscribe(threadMode = ThreadMode.PostThread)public void onPostThread(FirstEvent event) {    Log.e("TAG", "PostThread: " + Thread.currentThread().getName());}

在SecondActivity发送事件(主线程中发送):

EventBus.getDefault().post(new FirstEvent("啦啦啦"));

执行结果如下:

Async: pool-1-thread-1MainThread: mainPostThread: mainBackgroundThread: pool-1-thread-2

如果是在子线程中发送:

new Thread(new Runnable() {    @Override    public void run() {        EventBus.getDefault().post(new FirstEvent("啦啦啦"));    }}).start();

执行结果如下:

BackgroundThread: Thread-450PostThread: Thread-450Async: pool-1-thread-1MainThread: main

如果先启动SecondActivity,后启动MainActivity:

@Overridepublic void onClick(View v) {    EventBus.getDefault().postSticky(new FirstEvent("啦啦啦"));    startActivity(new Intent(SecondActivity.this,MainActivity.class));}

确实只有onAsync方法收到了消息。

至此对EventBus的试验基本就结束了,各位可以自行选择不同的ThreadMode值,让订阅函数执行在不同的线程。根据需要选择是否需要sticky=true。

完整的MainActivity和SecondActivity代码如下(xml文件就不贴了,就一个Button):

public class MainActivity extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        EventBus.getDefault().register(this);        findViewById(R.id.btn).setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                startActivity(new Intent(MainActivity.this,                        SecondActivity.class));            }        });    }    @Override    protected void onDestroy() {        super.onDestroy();        EventBus.getDefault().unregister(this);    }    @Subscribe(threadMode = ThreadMode.Async, sticky = true, priority = 1)    public void onAsync(FirstEvent event) {        Log.e("TAG", "Async: " + Thread.currentThread().getName());    }    @Subscribe(threadMode = ThreadMode.BackgroundThread)    public void onBackgroundThread(FirstEvent event) {        Log.e("TAG", "BackgroundThread: " + Thread.currentThread().getName());    }    @Subscribe(threadMode = ThreadMode.MainThread)    public void onMainThread(FirstEvent event) {        Log.e("TAG", "MainThread: " + Thread.currentThread().getName());    }    @Subscribe(threadMode = ThreadMode.PostThread)    public void onPostThread(FirstEvent event) {        Log.e("TAG", "PostThread: " + Thread.currentThread().getName());    }}public class SecondActivity extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_second);        findViewById(R.id.second).setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                EventBus.getDefault().postSticky(new FirstEvent("Lai自星星的我"));                startActivity(new Intent(SecondActivity.this,MainActivity.class));            }        });    }}
使用场景二:完美替换Handler,在主线程更新UI,如下示例-模拟下载显示进度条
public class MainActivity extends Activity {    public ProgressBar progressBar = null;    public int time = 0;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                new Thread(new Runnable() {                    @Override                    public void run() {                        while (time<100){                            time += 15;                            EventBus.getDefault().post(new TestEvent(time));                            try {                                Thread.sleep(200);                            } catch (InterruptedException e) {                                e.printStackTrace();                            }                        }                    }                }).start();            }        });        progressBar = (ProgressBar) findViewById(R.id.progressbar);        EventBus.getDefault().register(this);    }    @Override    protected void onDestroy() {        super.onDestroy();        EventBus.getDefault().unregister(this);    }    @Subscribe(threadMode = ThreadMode.MAIN)    public void onEventMainThread(TestEvent event){        progressBar.setProgress(event.getMsg());    }}

当然EventBus的功能并不局限这两种,还可以替换各种CallBack回调接口、StrartActivityForResult()等功能。
EventBus封装类:
/** * @author  * @version 1.0 * @date 2016-3-31 上午10:59:22 * @describe EventBusUtils工具类 */public class EventBusUtils {    public static void register(Object subscriber) {        if (!EventBus.getDefault().isRegistered(subscriber)) {            EventBus.getDefault().register(subscriber);        }    }    public static void unregister(Object subscriber) {        if(EventBus.getDefault().isRegistered(subscriber)){            EventBus.getDefault().unregister(subscriber);        }    }    public static void sendEvent(EventBusEvent event) {        EventBus.getDefault().post(event);    }    public static void sendStickyEvent(EventBusEvent event) {        EventBus.getDefault().postSticky(event);    }    /**     * 通过code码区分事件类型     */    public static final class EventCode {        public static final int A = 0x111111;        public static final int B = 0x222222;        public static final int C = 0x333333;        public static final int D = 0x444444;        public static final int E = 0x555555;        // other more    }}
/** * @author  * @version 1.0 * @date 2017/5/12 17:01 * @describe EventBus事件类 * * 通过泛型<T>指定事件通信过程中的数据类型,code为事件码,使用的时候给不同的事件类型指定不同的code */public class EventBusEvent<T> {    private int code;    private T data;    public EventBusEvent(int code) {        this.code = code;    }    public EventBusEvent(int code, T data) {        this.code = code;        this.data = data;    }    public int getCode() {        return code;    }    public void setCode(int code) {        this.code = code;    }    public T getData() {        return data;    }    public void setData(T data) {        this.data = data;    }}

最后,使用EventBus框架时候记得添加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);}
0 0
原创粉丝点击