EventBus3.0带你乐翻天

你还在为刷新ui伤透脑筋吗?你还在琢磨如何使用接口回调或者handle来实现吗?如果你想到了使用观察者模式,那么一个很屌的Android开源框架EventBus:主要功能是替代Intent、Handler、BroadCast在Fragment、Activity、Service、线程之间传递消息。他的最牛逼优点是开销小,代码简洁,解耦代码。

如果你没有使用过eventBus那么很遗憾你错过了很多,不过没有关系3.0的正式发布,使用没有什么大不一样只是性能更好。个人建议直接使用3.0.0的版本,也不要去使用2.4和3.0beta1的版本了

看图说话:
EventBus是一款针对Android优化的发布/订阅(publish/subscribe)事件总线。

EventBus作为一个消息总线,有三个主要的元素:

  • Event:事件。可以是任意类型的对象
  • Subscriber:事件订阅者,接收特定的事件。在EventBus中,使用约定来指定事件订阅者以简化使用。即所有事件订阅都都是以onEvent开头的函数,具体来说,函数的名字是onEvent,onEventMainThread,onEventBackgroundThread,onEventAsync这四个,这个和
    ThreadMode(下面讲)有关。
  • Publisher:事件发布者,用于通知 Subscriber 有事件发生。可以在任意线程任意位置发送事件,直接调用eventBus.post(Object) 方法,可以自己实例化 EventBus
    对象,但一般使用默认的单例就好了:EventBus.getDefault(), 根据post函数参数的类型,会自动调用订阅相应类型事件的函数。

EventBus使用详解

EventBus使用步骤

(1)引入EventBus:
  • 引入eventbus:2.4.0(回顾老版本)

    compile ‘de.greenrobot:eventbus:2.4.0’

  • 引入eventbus:3.0.0-beta1

    compile ‘de.greenrobot:eventbus:3.0.0-beta1’

  • 引入eventbus:3.0.0

    compile ‘org.greenrobot:eventbus:3.0.0’

(2)定义一个消息类,该类可以不继承任何基类也不需要实现任何接口。如:
public class MessageEvent {
    ......
}
(3)在需要订阅事件的地方注册事件

EventBus.getDefault().register(this);

(4)发送事件:即发送消息

EventBus.getDefault().post(messageEvent);

(5)处理消息

在3.0之前,EventBus还没有使用注解方式。消息处理的方法也只能限定于onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,分别代表四种线程模型。而在3.0之后,消息处理的方法可以随便取名,但是需要添加一个注解@Subscribe,并且要指定线程模型(beta1默认为PostThread,正式版默认为POSTING),四种线程模型,下面会讲到。
注意,事件处理函数的访问权限必须为public,否则会报异常。

EventBus3.0与EventBus2.4的区别
  • EventBus 2.4在使用方式
 public void onEvent(MessageEvent event) {
// 事件在哪个线程发布出来的,onEvent就会在这个线程中运行,也就是说发布事件和接收事件线程在同一个线程。使用这个方法时,在onEvent方法中不能执行耗时操作,如果执行耗时操作容易导致事件分发延迟。
    }
 public void onEventMainThread(MessageEvent event) {
// 不论事件是在哪个线程中发布出来的,onEventMainThread都会在UI线程中执行,接收事件就会在UI线程中运行,这个在Android中是非常有用的,因为在Android中只能在UI线程中跟新UI,所以在onEvnetMainThread方法中是不能执行耗时操作的。
    }
public void onEventBackgroundThread(MessageEvent event){
//那么如果事件是在UI线程中发布出来的,那么onEventBackground就会在子线程中运行,如果事件本来就是子线程中发布出来的,那么onEventBackground函数直接在该子线程中执行。
    }
public void onEventAsync(MessageEvent event){
//使用这个函数作为订阅函数,那么无论事件在哪个线程发布,都会创建新的子线程在执行onEventAsync.
    }
  • 在EventBus 3.0.0的使用是这样的
    (1) beta1版的写法
  @Subscribe(threadMode = ThreadMode.PostThread) //3.0.0-beta1
    public void onMessageEventPost(UserEvent event) {
    //默认方式, 在发送线程执行
    }
 @Subscribe(threadMode = ThreadMode.MainThread) 
    public void onMessageEventMain(UserEvent event) {
    //在ui线程执行
    }
   @Subscribe(threadMode = ThreadMode.BackgroundThread)
    public void onMessageEventBackground(UserEvent event) {
     //在后台线程执行
    }
 @Subscribe(threadMode = ThreadMode.Async) 
    public void onMessageEventAsync(UserEvent event) {
    //强制在后台执行
    }

(2) 正式版的写法

  @Subscribe(threadMode = ThreadMode.POSTING) //3.0.0
    public void onMessageEventPost(UserEvent event) {
    //默认方式, 在发送线程执行
    }
 @Subscribe(threadMode = ThreadMode.MAIN) 
    public void onMessageEventMain(UserEvent event) {
    //在ui线程执行
    }
   @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onMessageEventBackground(UserEvent event) {
     //在后台线程执行
    }
 @Subscribe(threadMode = ThreadMode.ASYNC) 
    public void onMessageEventAsync(UserEvent event) {
    //强制在后台执行
    }
(6)取消消息订阅

EventBus.getDefault().unregister(this);

(7)代码混淆
#EventBus
 -keepclassmembers class ** {
    public void onEvent*(**);
    void onEvent*(**);
 }

看下简单实现的效果(带妹子的手机桌面):

看下具体的代码使用:

package com.losileeya.eventbusapp;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.losileeya.eventbusapp.event.EventBusEvents;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button btn_first,btn_second,btn_third,btn_sticky;
    private TextView tv_toast;
    private TextView tv_default,tv_main,tv_background,tv_asy;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        EventBus.getDefault().register(this);

        btn_first = (Button) findViewById(R.id.btn_first);
        btn_second = (Button) findViewById(R.id.btn_second);
        btn_third = (Button) findViewById(R.id.btn_third);
        btn_sticky= (Button) findViewById(R.id.btn_sticky);
        tv_toast= (TextView) findViewById(R.id.tv_toast);
        tv_default= (TextView) findViewById(R.id.tv_default);
        tv_main= (TextView) findViewById(R.id.tv_main);
        tv_background= (TextView) findViewById(R.id.tv_background);
        tv_asy= (TextView) findViewById(R.id.tv_asy);
        btn_first.setOnClickListener(this);
        btn_second.setOnClickListener(this);
        btn_third.setOnClickListener(this);
        btn_sticky.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        Intent intent;
        switch (v.getId()){
            case R.id.btn_first:
                intent = new Intent(MainActivity.this,FirstActivity.class);
                startActivity(intent);
                break;
            case R.id.btn_second:
                intent = new Intent(MainActivity.this,SecondActivity.class);
                startActivity(intent);
                break;
            case R.id.btn_third:
                intent = new Intent(MainActivity.this,ThirdActivity.class);
                startActivity(intent);
                break;
            case R.id.btn_sticky:
                intent = new Intent(MainActivity.this,StickyActivity.class);
                startActivity(intent);
                break;
        }
    }
    @Subscribe(threadMode = ThreadMode.MAIN,priority = 1)
    public void onMessageMain(EventBusEvents.FirstEvent firstEvent){
        tv_toast.setText(firstEvent.getValue());
        Toast.makeText(this, firstEvent.getValue(),Toast.LENGTH_SHORT).show();
        Log.e("zy", "onEventMainThread-->" +"priority = 1,"+ Thread.currentThread().getId());
        tv_main.setText(Thread.currentThread().getName()+"---->"+Thread.currentThread().getId());
    }
    /** * 使用onEvent来接收事件,那么接收事件和分发事件在一个线程中执行 * param event */
    @Subscribe(threadMode = ThreadMode.POSTING,priority = 2)
    public void onPost(EventBusEvents.FirstEvent firstEvent) {
        Log.e("zy", "onEventPost-->" +"priority = 2,"+ Thread.currentThread().getId());
        tv_default.setText(Thread.currentThread().getName()+"---->"+Thread.currentThread().getId());
    }



    /** * 使用onEventBackgroundThread来接收事件,如果分发事件在子线程运行,那么接收事件直接在同样线程 * 运行,如果分发事件在UI线程,那么会启动一个子线程运行接收事件 * param event */
    @Subscribe(threadMode = ThreadMode.BACKGROUND,priority = 3)
    public void onBackgroundThread(EventBusEvents.FirstEvent firstEvent)
    {
        Log.e("zy", "onEventBackgroundThread-->" +"priority = 3,"+ Thread.currentThread().getId());
        tv_background.setText(Thread.currentThread().getName()+"---->"+Thread.currentThread().getId());
    }
    /** * 使用onEventAsync接收事件,无论分发事件在(UI或者子线程)哪个线程执行,接收都会在另外一个子线程执行 * param event */
    @Subscribe(threadMode = ThreadMode.ASYNC,priority = 4)
    public void onAsync(EventBusEvents.FirstEvent firstEvent) {
        Log.e("zy", "onEventAsync-->"+"priority = 4," + Thread.currentThread().getId());
        tv_asy.setText(Thread.currentThread().getName()+"---->"+Thread.currentThread().getId());
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }
}
package com.losileeya.eventbusapp;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

import com.losileeya.eventbusapp.event.EventBusEvents;

import org.greenrobot.eventbus.EventBus;


public class FirstActivity extends AppCompatActivity {
    private Button btn_showDownLoad;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
        btn_showDownLoad = (Button) findViewById(R.id.btn_toast);
        btn_showDownLoad.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        EventBus.getDefault().post(new EventBusEvents.FirstEvent("我是从网络下载的文本"));
                    }
                }).start();
            }
        });
    }
}

可以看出哪里需要发送消息,那么就必须使用:

EventBus.getDefault().post(your event)

然后你只需要订阅就好了:

   @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageMain(EventBusEvents.FirstEvent firstEvent){
        tv_toast.setText(firstEvent.getValue());
        Toast.makeText(this, firstEvent.getValue(),Toast.LENGTH_SHORT).show();
    }

事件的优先级处理

接收事件方法可以通过@Subscribe(priority = 1)
priority的值来决定接收事件的顺序,数值越高优先级越大,默认优先级为0.

(注意这里优先级设置只有在同一个线程模型才有效)

   @Subscribe(threadMode = ThreadMode.ASYNC,priority = 4)
    public void onAsync(EventBusEvents.FirstEvent firstEvent) {
        Log.e("zy", "onEventAsync-->"+"priority = 4," + Thread.currentThread().getId());
        tv_asy.setText(Thread.currentThread().getName()+"---->"+Thread.currentThread().getId());
    }
    @Subscribe(threadMode = ThreadMode.ASYNC,priority = 2)
    public void onAsync1(EventBusEvents.FirstEvent firstEvent) {
        Log.e("zy", "onEventAsync1-->"+"priority = 2," + Thread.currentThread().getId());
        tv_asy.setText(Thread.currentThread().getName()+"---->"+Thread.currentThread().getId());
    }

同一模式下优先级高的先执行,看图:

这里写图片描述

  @Subscribe(threadMode = ThreadMode.MAIN,priority = 1)
    public void onMessageMain(EventBusEvents.FirstEvent firstEvent){
        tv_toast.setText(firstEvent.getValue());
        Toast.makeText(this, firstEvent.getValue(),Toast.LENGTH_SHORT).show();
        Log.e("zy", "onEventMainThread-->" +"priority = 1,"+ Thread.currentThread().getId());
        tv_main.setText(Thread.currentThread().getName()+"---->"+Thread.currentThread().getId());
    }
    /** * 使用onEvent来接收事件,那么接收事件和分发事件在一个线程中执行 * param event */
    @Subscribe(threadMode = ThreadMode.POSTING,priority = 2)
    public void onPost(EventBusEvents.FirstEvent firstEvent) {
        Log.e("zy", "onEventPost-->" +"priority = 2,"+ Thread.currentThread().getId());
        tv_default.setText(Thread.currentThread().getName()+"---->"+Thread.currentThread().getId());
    }



    /** * 使用onEventBackgroundThread来接收事件,如果分发事件在子线程运行,那么接收事件直接在同样线程 * 运行,如果分发事件在UI线程,那么会启动一个子线程运行接收事件 * param event */
    @Subscribe(threadMode = ThreadMode.BACKGROUND,priority = 3)
    public void onBackgroundThread(EventBusEvents.FirstEvent firstEvent)
    {
        Log.e("zy", "onEventBackgroundThread-->" +"priority = 3,"+ Thread.currentThread().getId());
        tv_background.setText(Thread.currentThread().getName()+"---->"+Thread.currentThread().getId());
    }
    /** * 使用onEventAsync接收事件,无论分发事件在(UI或者子线程)哪个线程执行,接收都会在另外一个子线程执行 * param event */
    @Subscribe(threadMode = ThreadMode.ASYNC,priority = 4)
    public void onAsync(EventBusEvents.FirstEvent firstEvent) {
        Log.e("zy", "onEventAsync-->"+"priority = 4," + Thread.currentThread().getId());
        tv_asy.setText(Thread.currentThread().getName()+"---->"+Thread.currentThread().getId());
    }

不同ThreadMode运行下结果看图:

事件优先级不影响不同线程模型订阅事件顺序.

EventBus粘性事件

除了上面讲的普通事件外,EventBus还支持发送黏性事件。简单讲,就是在发送事件之后再订阅该事件也能收到该事件.粘性事件能够收到订阅之前发送的消息。但是它只能收到最新的一次消息,比如说在未订阅之前已经发送了多条黏性消息了,然后再订阅只能收到最近的一条消息。

注册和注销方法一样,发送事件和订阅事件有些区别

发送事件

EventBus.getDefault().postSticky(you event);

订阅粘性事件 默认sticky为false

@Subscribe(sticky = true)
    public void onPostThread(Event.Message msg) {
        .....
    }

看荔枝:

package com.losileeya.eventbusapp;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

/** * Created on 2016/4/14. */
public class StickyActivity extends AppCompatActivity {
    private int index = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sticky);

        Button bt_send = (Button) findViewById(R.id.bt_send);
        Button bt_regist = (Button) findViewById(R.id.bt_regist);
        Button bt_unregist = (Button) findViewById(R.id.bt_unregist);

        bt_send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.i("zy", "POSTING---->" + index);
                EventBus.getDefault().postSticky("zy---->" + index++);
            }
        });
        bt_regist.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().register(StickyActivity.this);
            }
        });
        bt_unregist.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().unregister(StickyActivity.this);
            }
        });


    }


    @Subscribe(threadMode = ThreadMode.POSTING,sticky = true)
    public void onPostThread(String msg) {
        Log.i("zy", "onEventPostThread---->" + msg);
    }

    @Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
    public void onMainThread(String msg) {
        Log.i("zy", "onEventMainThread---->" + msg);
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND,sticky = true)
    public void onBackgroundThread(String msg) {
        Log.i("zy", "onEventBackgroundThread---->" + msg);
    }

    @Subscribe(threadMode = ThreadMode.ASYNC,sticky = true)
    public void onAsyncThread(String msg) {
        Log.i("zy", "onEventAsyncThread---->" +msg);
    }
}

activity_sticky.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >
    <Button  android:id="@+id/bt_send" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="发送事件" />
    <Button  android:id="@+id/bt_regist" android:layout_marginTop="10dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="注册" />
    <Button  android:id="@+id/bt_unregist" android:layout_marginTop="10dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="注销" />
</LinearLayout>

看我的执行步骤:

  • 首先在未订阅的情况下点击发送按钮发送一个黏性事件,然后点击订阅,打印如下: —>

  • 我们连续点击发送事件按钮发送黏性事件,然后再点击注册按钮订阅,打印结果如下:—>

EventBus3.0带你乐翻天_第1张图片
是不是接到了最后一个事件。

取消订阅事件

你可以取消事件订阅通过调用cancelEventDelivery(Object event)方法,任何进一步的事件交付将被取消,后续用户不会接收到事件,但是该方法只有在ThreadMode.PostThread事件处理方法中调用才有效.
就讲到这里了》》》

注意:

  1. @Subscribe 下的方法必须为public
  2. postSticky()发送的粘性消息订阅时必须@Subscribe(sticky = true)否则接收不到
  3. 发送的event事件是object类
  4. @Subscribe(priority = 1) 使用时优先级默认为0,然后只有统一模式下设置优先级才有效果,自己看着合理使用

demo传送门:EventBusApp
觉得还不错的帮忙顶一下,大家相互学习一下,哈哈哈。

你可能感兴趣的:(android,开源框架)