EventBus使用详解

作者: 选一个昵称这么难 | 来源:发表于2017-09-05 12:56 被阅读486次

EventBus是一款针对优化的发布/订阅事件总线。简化了应用程序内各组件间、组件与后台线程间的通信。优点是开销小,代码更优雅,以及将发送者和接收者解耦。
使用场景:
假如有两个页面A和B,A页面变化后要让B页面也发生变化,怎么办?可以发广播,但是比较重量级,因此我们的主角登场了
使用步骤:
(1)添加依赖:
在app的build.gradle里面

dependencies {
    ...
    compile 'org.greenrobot:eventbus:3.0.0'
}

(2)在订阅事件所属的Activity或者fragment里面注册,一般写在onCreate()方法里

EventBus.getDefault().register(this);

注意:在页面销毁的时候要注销EventBus,一般在onDestory()方法里

EventBus.getDefault().unregister(this);

(3)在事件产生的地方(可能不好理解,看例子就行)调用

EventBus.getDefault().post(new Object());

(4)在事件订阅的地方调用

@Subscribe(threadMode = ThreadMode.MAIN)
    public void updateUI(){
        //在这里处理相应的逻辑
}

下面先看个例子再细说
A页面展示用户信息,点击按钮进入B页面,在B页面编辑用户信息,编辑完成后点击按钮退出B按钮退出B页面,同时A页面的信息是最新的
先看下效果:

最初A页面 进入B并修改 点击完成回到A页面

先看下A页面实现:

public class Activity_A extends AppCompatActivity {

    private TextView tv_name;
    private TextView tv_age;
    private Button button;

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

        EventBus.getDefault().register(this);

        tv_name = (TextView) findViewById(R.id.tv_name);
        tv_age = (TextView) findViewById(R.id.tv_age);
        button = (Button) findViewById(R.id.bt_edit);
        //进入编辑页面,要把这个页面的信息通过intent传递过去
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(Activity_A.this,Activity_B.class);
                intent.putExtra("name",tv_name.getText().toString().trim());
                intent.putExtra("age",tv_age.getText().toString().trim());
                startActivity(intent);
            }
        });

    }
    //B页面编辑完信息,使用EventBus发布信息,该方法会接受信息并更新用户信息
    //EventBus3.0之后使用注解的方式,这样方法的名字可以任意写,比如这里的updateUserInfo(这个参数和B页面post方法的参数类型一定一样)
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void updateUserInfo(Person person){
        tv_name.setText(person.getName());
        tv_age.setText(person.getAge());
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }
}
public class Activity_B extends AppCompatActivity {

    private EditText et_name;
    private EditText et_age;
    private Button bt_finish;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        //注意:该页面只是发出消息,并没有接受消息,所以不需要也不能有EventBus.getDefault().register(this);
        et_name = (EditText) findViewById(R.id.et_name);
        et_age = (EditText) findViewById(R.id.et_age);
        bt_finish = (Button) findViewById(R.id.bt_finish);
        //获取A页面传递过来的值,并初始化页面
        Intent intent = getIntent();
        et_name.setText(intent.getStringExtra("name"));
        et_age.setText(intent.getStringExtra("age"));
        //点击完成按钮,关闭该页面回到A页面
        bt_finish.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Person person = new Person();
                person.setAge(et_age.getText().toString().trim());
                person.setName(et_name.getText().toString().trim());
                //这个person对象就会传到A页面updateUserInfo(Person person)中的参数person里面
                EventBus.getDefault().post(person);
                Activity_B.this.finish();
            }
        });
    }
}
//一个javabean
class Person{
    private String age;
    private String name;

    public Person() {
    }

    public Person(String age, String name) {
        this.age = age;
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

布局很简单,就不贴了

几个细节说一下:
(1)除了一般的post方法,我们还会使用

EventBus.getDefault().postSticky(object);

所谓粘性事件,比如上面的例子,当我在B页面编辑完信息回到A之后不想马上更新用户信息,而是希望点击一个按钮之后再更新,

A页面增加更新按钮

修改A的代码:
不同之处已经添加注释,用!!!包裹

public class Activity_A extends AppCompatActivity {

    private TextView tv_name;
    private TextView tv_age;
    private Button button;
    private Button bt_update;

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

        //!!!一开始不会注册!!!
//        EventBus.getDefault().register(this);

        tv_name = (TextView) findViewById(R.id.tv_name);
        tv_age = (TextView) findViewById(R.id.tv_age);
        button = (Button) findViewById(R.id.bt_edit);
        bt_update = (Button) findViewById(R.id.bt_update);
        //!!!点击更新按钮之后才注册!!!
        bt_update.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().register(Activity_A.this);
            }
        });
        //进入编辑页面,要把这个页面的信息通过intent传递过去
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(Activity_A.this,Activity_B.class);
                intent.putExtra("name",tv_name.getText().toString().trim());
                intent.putExtra("age",tv_age.getText().toString().trim());
                startActivity(intent);
            }
        });

    }
    //B页面编辑完信息,使用EventBus发布信息,该方法会接受信息并更新用户信息
    //EventBus3.0之后使用注解的方式,这样方法的名字可以任意写,比如这里的updateUserInfo(这个参数和B页面post方法的参数类型一定一样)
    //!!!这里多了一个sticky = true,说明接收一个粘性事件!!!
    @Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
    public void updateUserInfo(Person person){
        tv_name.setText(person.getName());
        tv_age.setText(person.getAge());
    }

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

B页面只改动一个地方:

EventBus.getDefault().postSticky(person);

(2)订阅事件的优先级
我们在A页面写两个方法接受订阅事件,看谁先执行,注意我们加了priority这个属性

@Subscribe(threadMode = ThreadMode.MAIN,priority = 100)
    public void updateUserInfo(Person person){
        System.out.println("updateUserInfo");
        tv_name.setText(person.getName());
        tv_age.setText(person.getAge());
    }
    @Subscribe(threadMode = ThreadMode.MAIN,priority = 10000)
    public void updateUserInfo2(Person person){
        System.out.println("updateUserInfo2");
        tv_name.setText(person.getName());
        tv_age.setText(person.getAge());
    }

结果:
priority值大的方法先执行

13:50:45.745 15870-15870/com.dgtech.sss.eventbusdemo I/System.out: updateUserInfo2
13:50:45.746 15870-15870/com.dgtech.sss.eventbusdemo I/System.out: updateUserInfo

priority值越大,优先级越高,默认值是0
(3)四种threadMode
①ThreadMode.MAIN
无论在哪个线程post(),订阅方法都在主线程执行

A修改:
@Subscribe(threadMode = ThreadMode.MAIN)
    public void updateUserInfo(Person person){
        System.out.println("订阅方法执行的线程是:"+Thread.currentThread().getName());
        tv_name.setText(person.getName());
        tv_age.setText(person.getAge());
    }
B修改:
EventBus.getDefault().post(person);
System.out.println("post线程是: "+Thread.currentThread().getName());

结果:

14:00:07.239 23105-23105/com.dgtech.sss.eventbusdemo I/System.out: 订阅方法执行的线程是:main
14:00:07.239 23105-23105/com.dgtech.sss.eventbusdemo I/System.out: post线程是: main

②ThreadMode.POSTING
在哪个线程post就在哪个线程执行订阅方法

A修改:
@Subscribe(threadMode = ThreadMode.POSTING)
    public void updateUserInfo(Person person){
        System.out.println("订阅方法执行的线程是:"+Thread.currentThread().getName());
        tv_name.setText(person.getName());
        tv_age.setText(person.getAge());
    }
B修改:
new Thread(){
       @Override
      public void run() {
             EventBus.getDefault().post(person);
             System.out.println("post线程是: "+Thread.currentThread().getName());
        }
}.start();

结果:

14:03:55.650 26605-26800/com.dgtech.sss.eventbusdemo I/System.out: 订阅方法执行的线程是:Thread-2
14:03:55.652 26605-26800/com.dgtech.sss.eventbusdemo I/System.out: post线程是: Thread-2

③ThreadMode.BACKGROUND
如果post实在主线程,则订阅方法会新创建一个子线程并在该子线程执行;如果post在子线程,那么订阅方法就在该子线程执行
还是上面②的代码
执行结果:

14:09:09.293 31005-31176/com.dgtech.sss.eventbusdemo I/System.out: 订阅方法执行的线程是:Thread-2
14:09:09.296 31005-31176/com.dgtech.sss.eventbusdemo I/System.out: post线程是: Thread-2

修改上面的代码,把post方法放到主线程:

EventBus.getDefault().post(person);
System.out.println("post线程是: "+Thread.currentThread().getName());

结果:

14:10:47.001 544-544/com.dgtech.sss.eventbusdemo I/System.out: post线程是: main
14:10:47.002 544-1078/com.dgtech.sss.eventbusdemo I/System.out: 订阅方法执行的线程是:pool-1-thread-1

④ThreadMode.ASYNC
无论post在哪个线程执行,订阅方法都新创建线程来执行
还是③的代码
执行结果:

14:13:19.439 4641-4891/com.dgtech.sss.eventbusdemo I/System.out: post线程是: Thread-2
14:13:19.439 4641-4892/com.dgtech.sss.eventbusdemo I/System.out: 订阅方法执行的线程是:pool-1-thread-1

以上大概就是项目中会涉及到EventBus的使用了,后面我们会分析EventBus的原理

相关文章

  • EventBus

    《EventBus使用详解(一)——初步使用EventBus》 《EventBus使用详解(二)——EventBu...

  • 为什么会用到EventBus,EventBus的源码详解与架构分

    面试官: 为什么会用到EventBus,EventBus的源码详解与架构分析,使用EventBus会造成什么弊端...

  • 自己实现简单的EventBus功能

    1、下面是EventBus3.0的一些用法和源码分析 EventBus使用详解 EventBus源码解析 2、接...

  • EventBus 使用详解

    EventBus 使用详解 概述 EventBus是一个Android事件发布/订阅框架,通过解耦发布者和订阅者简...

  • EventBus源码详解,看这一篇就够了

    之前写过一篇关于EventBus的文章,大家的反馈还不错(EventBus3.0使用详解),如果你还没有使用过Ev...

  • EventBus使用详解

    1、EventBus.getDefault().postSticky(new Message(infoList.g...

  • EventBus使用详解

    基本使用 (1)自定义一个类,可以是空类,比如: (2)在要接收消息的页面注册: (3)发送消息 (4)接受消息的...

  • EventBus使用详解

    前言:EventBus出来已经有一段时间了,github上面也有很多开源项目中使用了EventBus。所以抽空学习...

  • EventBus使用详解

    概述 EventBus是一个Android事件发布/订阅框架,通过解耦发布者和订阅者简化Android事件传递,这...

  • EventBus使用详解

    前言 最近在公司做一个类似于手机工厂模式的一个项目,用来检测其他各个App是否正常工作,所以要求是尽可能的轻量级,...

网友评论

本文标题:EventBus使用详解

本文链接:https://www.haomeiwen.com/subject/jodujxtx.html