EventBus 3.0 事件总线介绍

很早就知道这个库,这次不能放过他了要好好学习下。EventBus到底是什么呢?EventBus是一个小巧好用的事件总线框架。类似的事件总线框架还有otto。我的理解就是用来方便的在Activity,Fragment,Service等类之间方便的传递数据。EventBus可以实现Android Broadcast(广播)的功能,用Intent类传值的功能,startActivityForResult方法的功能。EventBus在我们的项目中还是值得使用,可以减少代码之间的耦合,使我们的代码更加简洁,方便做单元测试,效率也不用担心。下面介绍EventBus的使用。

EventBus事件流程图:
image

EventBus github地址:
https://github.com/greenrobot/EventBus

EventBus官方地址
http://greenrobot.org/eventbus/

一:在Android Studio中配置

在App层的build.gradle文件中加入:compile ‘org.greenrobot:eventbus:3.0.0’

二:只需三步就能实现EventBus的使用

1.定义事件

事件就是一个POJO (plain old Java object)。只有对属性的定义,没有其他东西。

public class MessageEvent {

    public final String message;

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

2.订阅事件

最简单的订阅事件只需在类的方法上加上一个注解@Subscibe,当然这个注解可以设置参数

// This method will be called when a SomeOtherEvent is posted
@Subscribe
public void handleSomethingElse(SomeOtherEvent event) {
    doSomethingWith(event);
}

当然订阅事件首先需要进行对事件订阅者进行注册。在开发中我们一般是在Activity或者Fragment中注册。注册需要结合生命周期进行。

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

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

3.发布事件

我们可以在代码的任何地方发布事件,所有事件的订阅者,只要事件类型匹配,就能收到发布的时间。

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

只需三步我们就能用EventBus实现事件的订阅和发布,用EventBus来传递数据真是方便。

三:EventBus实现Activity的startActivtyForResult功能

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        EventBus.getDefault().register(this);

        // 实现startActivityForResult功能
        findViewById(R.id.button).setOnClickListener(new              
            View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this,        
                SecondActivity.class));
            }
        });


    }

    @Subscribe
    public void onMessage(MessageEvent event) {
        Toast.makeText(this, event.getMessage(), Toast.LENGTH_SHORT).show();
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageMainThread(MessageEvent event) {
        Log.e("TAG", " message = " + event.getMessage());
    }


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

我们在MainActivity 的onCreate方法中进行了注册,在onDestroy方法中解除了注册。onMessage方法和onMessageMainThread方法用来接收事件。我们的事件对象是MessageEvent。

public class MessageEvent {

    private String message;

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

    public String getMessage() {
        return message;
    }
}

这个是我们的事件对象类。

public class SecondActivity extends AppCompatActivity {

    private Button button;
    private EditText editText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        button = (Button) findViewById(R.id.button);
        editText = (EditText) findViewById(R.id.edit_text);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().post(new MessageEvent(editText.getText().toString()));
                SecondActivity.this.finish();
            }
        });

    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
}

这个类的布局中有两个控件一个Button和一个EditText,点击按钮,把输入框中的字符转换成一个事件对象MessageEvent发送给事件的订阅者(在MainActiviy中)。这样在SecondActivity 类中的数据就被发送到MainActivity中去了。这个过程很像在MainActiviy通过startActivityForResult()方法跳转到SecondActivity中,然后在SecondActivity中获取数据,再通过MainActivity类的onActivityResult()方法获取来自SecondActivity 类的数据这一过程。上面的这个例子中的注解@Subscribe有一个参数threadMode且值是ThreadMode.MAIN。这个注解表示被注解的方法是运行在系统的主线程中的也就是UI线程,这样很方便我们对控件TextView、Button等的设置。

四:EventBus的四种线程模型

在上面的例子中我们提到一种线程模型ThreadMode.MAIN表示,被注解的方法是运行在主线程中的。下面分别介绍着四种线程模型:

  • ThreadMode.POSTING:事件在哪个线程发布出来的,onEvent就会在这个线程中运行,也就是说发布事件和接收事件线程在同一个线程。使用这个方法时,在onEvent方法中不能执行耗时操作,如果执行耗时操作容易导致事件分发延迟。这是默认方式。

  • ThreadMode.MAIN:不论事件是在哪个线程中发布出来的,onEventMainThread都会在UI线程中执行,接收事件就会在UI线程中运行,这个在Android中是非常有用的,因为在Android中只能在UI线程中跟新UI,所以在onEvnetMainThread方法中是不能执行耗时操作的。

  • ThreadMode.BACKGROUND:如果事件是在UI线程中发布出来的,那么onEventBackground就会在子线程中运行,如果事件本来就是子线程中发布出来的,那么onEventBackground函数直接在该子线程中执行。
  • ThreadMode.ASYNC:无论事件在哪个线程发布,都会创建新的子线程在执行.

五:EventBus的Sticky事件

我们知道在Android开发中有一个重要的组件广播,有一种广播叫粘性广播。普通的广播,我们先要注册广播,这样才能接收到发送过来的广播,如果是先发送后注册,那么发送过来的广播就接收不到。粘性广播,这种广播可以先发送后注册,就是说系统会保留之前发送的广播,后来的注册者也能接受到该广播。

发送粘性广播

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

接受粘性广播,参数sticky的值必须为true,默认为false

// UI updates must run on MainThread
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event) {   
    textField.setText(event.message);
}

EventBus会保留粘性广播,不用可以删除,先获取,后移除

MessageEvent stickyEvent = EventBus.getDefault().getStickyEvent(MessageEvent.class);
// Better check that an event was actually posted before
if(stickyEvent != null) {
    // "Consume" the sticky event
    EventBus.getDefault().removeStickyEvent(stickyEvent);
    // Now do something with it
}

六:EventBus发送sticky事件模拟Intent发送数据

点击按钮,从两个EditText中获取数据,发送一个粘性事件,先发送

public class MakeUserInfoActivity extends AppCompatActivity {

    private Button mButton;
    private EditText mEditName;
    private EditText mEditAge;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_make_user_info);

        initWidgets();

        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                // 下面两行代码,模拟Intent传递数据,一个User对象
                User user = new User();
                user.setName(mEditName.getText().toString());
                user.setAge(mEditAge.getText().toString());

                EventBus.getDefault().postSticky(user);
                startActivity(new Intent(MakeUserInfoActivity.this,
                        ShowUserInfoActivity.class));
            }
        });

    }

    private void initWidgets() {
        mEditName = (EditText) findViewById(R.id.et_name);
        mEditAge = (EditText) findViewById(R.id.et_age);
        mButton = (Button) findViewById(R.id.button);
    }
}

注册事件,后注册,我们在onDestroy()方法中移除这个粘性事件

public class ShowUserInfoActivity extends AppCompatActivity {

    private TextView mTextView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {



        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_show_user_info);

        mTextView = (TextView) findViewById(R.id.tv_user_info);


        // 注意要先初始化控件,防止onMessageEventMainThread方法执行的时候控件尚未初        始化,空指针异常
        EventBus.getDefault().register(this);

    }


    @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
    public void onMessageEventMainThread(User user) {


        Log.e("TAG", "User.name = " + user.getName());
        Log.e("TAG", "User.age = " + user.getAge());

        mTextView.setText(user.getName() + "-" + user.getAge());
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();


        if (EventBus.getDefault().getStickyEvent(User.class) != null) {
            EventBus.getDefault().removeStickyEvent(EventBus.getDefault().getStickyEvent(User.class));
        }

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

七:EventBus事件优先级

Android的广播有优先级的概念,EventBus事件总线框架也有这概念。
我在注解@Subscribe有个参数priority默认值是0,通过这个参数我们可以给订阅者加上优先级。数值越大,可以越优先获取传过来的事件。

@Subscribe(priority = 1);
public void onEvent(MessageEvent event) {
    ...
}

优先级高的可以,优先获取传来事件,之后还可以取消事件往优先级低的订阅者传递。在文章底部给出的两个代码中有关于优先级的例子。

// Called in the same thread (default)
@Subscribe
public void onEvent(MessageEvent event){
    // Process the event
    ...
    // Prevent delivery to other subscribers
    EventBus.getDefault().cancelEventDelivery(event) ;
}

八:EventBus框架的索引Index

subscriber index(订阅者索引是)EventBus3.0的新特新,它可以有效的提高代码的执行效率。订阅者索引是通过EventBus 的annotation processor在编译期间产生的。我们知道EventBus事件总线框架用到了注解,注解信息一般是在软件运行期通过反射获取的,这一过程损失了效率。EventBus 的annotation processor在编译期间就处理了注解的信息,提高了效率。

1.配置

对于Android Gradle Plugin version 2.2.0 或更高版本

android {
    defaultConfig {
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [ eventBusIndex 'com.example.myapp.MyEventBusIndex']
            }
        }
    }
}

dependencies {
    compile 'org.greenrobot:eventbus:3.0.0'
    annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.0.1'
}

com.example.myapp.MyEventBusIndex是在编译的时候产生的索引类。位置在
image

2.举例

public class MyApllication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
    }
}

我们在项目的入口,用addIndex()方法增加编译器产生的索引类。通过installDefaultEventBus()方法,我们可以像原来的样子获取EventBus实例。

事件注册类

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        EventBus.getDefault().register(this);

        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this, PostIndexActivity.class));
            }
        });

    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageMainThread(String str) {
        Log.e("TAG", "time got event = " + System.currentTimeMillis());
        Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
    }


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

事件发送类

public class PostIndexActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_post_index);


        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("TAG", "time send event = " + System.currentTimeMillis());
                EventBus.getDefault().post("hello world!");
                PostIndexActivity.this.finish();
            }
        });
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
}

在上面的例子中我们打印了事件发送和接收的时间,发现时间差在1毫秒以内,就是说发送事件和接收事件打印出来的时间一样。笔者通过测试发现,在模拟器和真机上用不用索引类,时间差都在1毫秒内。真是效率不是问题。

九:ProGard处理

当我们需要出正式版的时候,需要用ProGrard混淆代码和去掉不必要的代码。

-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);
}

参考文献:

https://github.com/greenrobot/EventBus

http://greenrobot.org/eventbus/

http://blog.csdn.net/z609933542/article/details/50953166

http://android.jobbole.com/81098/

http://android.jobbole.com/82049/

http://android.jobbole.com/82050/

源码下载:

EventBusDemo01

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页