EventBus的简单使用

github地址

EventBus是一个Android端优化的publish/subscribe消息总线,简化了应用程序内组件间、组件与后台线程间的通信

使用之前先添加依赖:

compile 'org.greenrobot:eventbus:3.0.0'//事件总线

定义消息实体类:

/**
 * 消息实体类  注意:传基本数据类型的值,事件函数的参数类型都是对应的包装类,如果你写成基本类型,就执行不到了
 */
public class MyMessageEvent {

    public String message;

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

代码如下:

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

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

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.btn_1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //发送事件:只要接受者的方法的参数 与 post提交的参数一致,就可以收到消息(结论)
                EventBus.getDefault().post(new MyMessageEvent("大家好!我是消息"));
            }
        });

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

    /**
     * 接收事件的方法
     * 注意:方法名随便写,因为是根据参数来判断接收者的
     *
     * @Subscribe : 该注解,代表该方法订阅Event发出来的事件 (不然怎么它知道 哪些方法是接收方呢)
     * 指定该方法执行的线程:
     * threadMode = ThreadMode.MAIN:不论事件是在哪个线程中发布出来的,该方法都会在UI线程中运行
     *              ThreadMode.POSTING:发布事件和接收事件线程在同一个线程执行 (默认模式)
     *              ThreadMode.BACKGROUND:如果事件是在UI线程中发布出来的,那么onEventBackground就会在子线程中运行,如果事件本来就是子线程中发布出来的,那么onEventBackground函数直接在该子线程中执行。
     *              ThreadMode.ASYNC:无论事件在哪个线程发布,都会创建新的子线程再执行
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void receiveEventMethod(MyMessageEvent event){
        Log.e("tag","我是第一个界面--" + event.message + ",当前线程:" + Thread.currentThread().getName());
    }

    /**
     * 当然,你也可以在onStart()方法注册,在onStop()方法移除
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);//移除监听
    }
}

说明:当我点击按钮执行发送事件,就会执行receiveEventMethod()方法

到这一步:事件的发送与接收就已经清楚了,现在测试,我在另一个界面发送事件,在MainActivity里能接收到吗?

说明:可以自己测试,效果如上,总之只要知道上面的结论就行了

到这里,你可能就有疑问了,参数一致,就都可以得到执行,但我想指定方法,只想其中一个方法执行,那又咋搞呢?

由于EventBus的设计就像观察者模式,它只管该执行怎么的方法,不管你的业务需求,不然咋叫消息总线呢,这样也违背了它的初衷吧。如果硬要执行指定的方法,就实现不了了吗?

我们先稍微修改下上面的消息实体类:

/**
 * 消息实体类
 */
public class MyMessageEvent {

    public String message;

    public String tag;//消息标记

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

    public MyMessageEvent(String message, String tag) {
        this.message = message;
        this.tag = tag;
    }
}

然后在发送消息的时候设置tag:

EventBus.getDefault().post(new MyMessageEvent("大家好!我是消息", MainActivity2.class.getName()));

现在就只需要在接收的方法中加个判断了

@Subscribe(threadMode = ThreadMode.MAIN)
    public void receiveEventMethod(MyMessageEvent event){
        //如果 tag一致 就说明希望执行该方法
        if(MainActivity.this.getClass().getName().equals(event.tag)){
            Log.e("tag","tag一致:" + event.message);
        }else{
            Log.e("tag","tag不一致");
        }
    }

这样,也就实现了想执行哪个类的接收方法就能执行哪个类的接收方法了

注意点:

由于注册多次会报错,所以你也可以这样写

if(!EventBus.getDefault().isRegistered(MainActivity.this)){
      EventBus.getDefault().register(MainActivity.this);//没有注册才注册监听  同理 反注册也一样可加判断
}else{
      Toast.makeText(MainActivity.this, "已经注册了,再注册会报错", Toast.LENGTH_SHORT).show();
}

上面讲的都是先注册了才能收到事件,下面介绍发送粘性事件(发送粘性事件后,再去注册也能收到参数一致的粘性事件,即 先发送,后注册再接收)

第一个界面:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.btn_1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //发送事件,只要接受者的方法的参数 与 post提交的参数一致,就可以收到消息
                EventBus.getDefault().post(new MyMessageEvent("大家好!我是消息"));
            }
        });

        findViewById(R.id.btn_2).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this,MainActivity2.class));
            }
        });
        findViewById(R.id.btn_3).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(!EventBus.getDefault().isRegistered(MainActivity.this)){
                    EventBus.getDefault().register(MainActivity.this);//没有注册才注册监听
                }else{
                    Toast.makeText(MainActivity.this, "已经注册了,再注册会报错", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
    @Subscribe(threadMode = ThreadMode.ASYNC)//非粘性事件
    public void receiveEventMethod(MyMessageEvent event){
        Log.e("tag","我是第一个界面的普通事件--" + event.message + ",当前线程:" + Thread.currentThread().getName());
    }

    @Subscribe(threadMode = ThreadMode.ASYNC ,sticky = true)//粘性事件
    public void receiveStickyEventMethod(MyMessageEvent event){
        Log.e("tag","我是第一个界面的粘性事件--" + event.message + ",当前线程:" + Thread.currentThread().getName());
    }

    /**
     * 当然,你也可以在onStart()方法注册,在onStop()方法移除
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);//移除监听
    }
}

第二个界面:

/**
 * 第二个界面
 */
public class MainActivity2 extends AppCompatActivity {

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

        EventBus.getDefault().register(this);//注册监听

        findViewById(R.id.btn_1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //发送粘性事件
                EventBus.getDefault().postSticky(new MyMessageEvent("粘性事件"));

                //移除粘性事件
                MyMessageEvent stickyEvent = EventBus.getDefault().getStickyEvent(MyMessageEvent.class);
                if(stickyEvent != null){
                    EventBus.getDefault().removeStickyEvent(stickyEvent);//移除
                    Toast.makeText(MainActivity2.this, "移除了粘性事件", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void receiveEventMethod(MyMessageEvent event){
        Log.e("tag","我是第二个界面的普通事件--" + event.message + ",当前线程:" + Thread.currentThread().getName());
    }

    @Subscribe(threadMode = ThreadMode.MAIN,sticky = true)//sticky 代表粘性事件
    public void receiveStickyEventMethod(MyMessageEvent event){
        Log.e("tag","我是第二个界面的粘性事件--" + event.message + ",当前线程:" + Thread.currentThread().getName());
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);//移除监听
    }

}

           第一个界面                                                                    第二个界面

当我点击第一个界面的“跳转到第二个ACTIVITY”按钮(第一个界面还没注册监听),然后点击第二个界面的“发送事件”按钮,效果如下:

如果我先在第一个界面注册,再点击第二个界面的发送事件按钮,日志如下:

结论1:发送粘性事件:如果发送之前注册了监听,那么不论是普通接受者,还是粘性事件接受者,都可以得到执行

当我点击第一个界面的“跳转到第二个ACTIVITY”按钮(第一个界面还没注册监听),然后点击第二个界面的“发送事件”按钮(注意:我把点击事件里移除事件的方法去掉了),再返回到第一个界面点击“注册监听”,效果如下:

结论2:发送粘性事件:如果发送粘性事件之后,再去注册事件的,只会执行接收粘性事件的方法,普通接收者方法不会执行

注意点:如果粘性事件不移除,当你再次注册的时候,还会接受到该粘性事件,所以最好还是接收到就移除

 缺陷

  1.反射,性能打折,效率低

  2.代码维护困难(找不到接收方)

  3.数据无法返回,单向传送

使用非粘性事件需要注意的问题:

1.如果是activity与Activity之间传递数据,当activity由于内存不足被销毁了后就接收不到事件了

2.如果是fragment与fragment所在的activity传递数据,肯定不会出现接收不到事件的情况(因为fragment存活,activity肯定也是存活的)

3.fragment与fragment通信,如果都属于同一个activity,那么肯定也不会出现接收不到事件的情况,所以很适合属于同一个activity的fragment之间进行数据传递

 

记录:

在父类注册,子类也可以收到事件,但是父类或者是子类必须有接收事件的方法

posted @ 2017-09-19 15:58  ts-android  阅读(431)  评论(0编辑  收藏  举报