Android开发Android开发经验谈Android技术知识

EventBus原理解析笔记以及案例实战(结合demo)

2019-08-09  本文已影响4人  凌川江雪

笔记概述

EventBus简介

  • 关于EventBus的优势

  • 简化组件间的通讯方式
    • 解耦合事件发送者和接收者
    • 使活动、碎片和后台的线程实现更高的执行效率
    • 防止复杂的有错误(倾向)的依赖以及生命周期的问题
  • 让你的代码简洁
  • 运行快
  • 库小

关于大项目,如果还是用Java/Android原生的调用,
两个Activity之间的通讯,
还用startActivity()/startActivityForResult()这类通信方式的话,
代码会非常的冗余
例如Activity和Fragment之间的通讯就需要不断地调用相关的函数
使用EventBus可以解除这些耦合;
否则如果代码耦合性非常大的话,
会大大增加后期维护的难度!


EventBus架构

EventBus概述


EventBus线程模型

ThreadMode

ThreadMode指定了会调用的函数,
只能有以下四种(因为每个订阅事件都是和一个线程模型相关的):
PostThread、 BackgroundThread、 MainThread、 Async

PostThread: 在相同的进程中做EventBus通信

相关地举一个案例

接下来新建一个项目,根据官方GitHub添加依赖,

implementation 'org.greenrobot:eventbus:3.1.1'

下面是主布局(Activity1):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/bt_toAc2"
        android:text="跳转到Activity2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>
public class MyEvent {

    public String msg;

    public MyEvent() {}

    public MyEvent(String msg) {
        this.msg = msg;
    }
}
    /**
     * 注册onEvent(),
     * 注意写上注解!
     */
    @Subscribe
    public void onEvent(MyEvent event) {
        popOutToast("接收到Event:" + event.msg);
    }
    /**
     * 封装弹出短时Toast提示
     * @param text 企图弹出的文本内容
     *
     */
    private void popOutToast(String text) {
        Toast.makeText(MainActivity.this,text,Toast.LENGTH_SHORT).show();
    }
        EventBus.getDefault().register(this);
    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }
public class MainActivity extends AppCompatActivity {

    private Button mButton;

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

        //使用EventBus的接收方法的活动,需要注册
        EventBus.getDefault().register(this);

        mButton = findViewById(R.id.bt_toAc2);
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                startActivity(intent);
            }
        });
    }

    /**
     * 注册onEvent(),
     * 注意写上注解!
     */
    @Subscribe
    public void onEvent(MyEvent event) {
        popOutToast("接收到Event:" + event.msg);
    }

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

    /**
     * 封装弹出短时Toast提示
     * @param text 企图弹出的文本内容
     *
     */
    private void popOutToast(String text) {
        Toast.makeText(MainActivity.this,text,Toast.LENGTH_SHORT).show();
    }
}

创建第二个活动SecondActivity,布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/bt_sendMsg"
        android:text="发送消息"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

java:

public class SecondActivity extends AppCompatActivity {

    private Button mButton;

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

        mButton = findViewById(R.id.bt_sendMsg);
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().post(new MyEvent("洞妖洞妖我是栋二!!!"));
            }
        });
    }
}

运行效果图:

Activity1:
跳到Activity2,点击按钮,弹出Toast:

补充

  • 另外一个需要注意的地方就是,
    EventBus.getDefault().register(this);系列的注册与反注册代码,
    onEvent()系列的接收函数是紧密绑定的;
    用时缺一不可,不用时存一不可,同生同灭;

    也就是说一个活动注册onEvent()系列的接收函数了,
    则必须用EventBus.getDefault().register(this);去注册,
    不然会报错;

    而一个活动它没有写onEvent()系列的接收函数,
    却用EventBus.getDefault().register(this);去注册了,
    同样也会报错!
    @Subscribe
    public void onEvent(MyEvent event) {

        //消耗时间模拟
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        popOutToast("接收到Event:" + event.msg);
    }

接着运行项目的话,
会发现我们在Activity2中点击发送消息的按钮之后,
要等到3秒钟,主线程才会刷新UI(弹出Toast),
这样子在实际运用中用户体验很差;

MainThread

使用:基于PostThread的代码,
加多一行(threadMode = ThreadMode.MAIN)即可:

    //MainThread
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEvent(MyEvent event) {

        //消耗时间模拟
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        popOutToast("接收到Event:" + event.msg);
    }

BackgroundThread

图解

对于PostThread和MainThread

一次执行

对于BackgroundThread

一一对应
顺序执行,前者执行,后者等待阻塞
    //BackgroundThread
    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onEvent(MyEvent event) {

        Log.d(TAG, "onEvent Start!!!!!!!! ");
        //消耗时间模拟
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Log.d(TAG, "onEvent End!!!!!!!! ");

//        popOutToast("接收到Event:" + event.msg);
    }
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEvent(MyEvent event) {

        Log.d(TAG, "onEvent Start!!!!!!!! ");
        //消耗时间模拟
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Log.d(TAG, "onEvent End!!!!!!!! ");

//        popOutToast("接收到Event:" + event.msg);
    }
  • PostThread/MainThread缺点:
    执行在主线程,
    事件的个数,事件的耗时,
    都需要做比较严格的限制

  • BackgroundThread缺点:
    运行在后台线程,不占用主线程资源,
    PostThread/MainThread好那么一点,
    但是还是没有解决——
    多个(>= 2 个)事件时,
    一次处理一个,依次处理,
    前者执行,后者等待阻塞
    的问题,
    不适合事件中有耗时较长的任务

Async adj.异步的;

sync n.同时,同步;

更改代码:

    //AsyncThread
    @Subscribe(threadMode = ThreadMode.ASYNC)
    public void onEvent(MyEvent event) {

        Log.d(TAG, "onEvent Start!!!!!!!! ");
        //消耗时间模拟
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Log.d(TAG, "onEvent End!!!!!!!! ");
    }
执行效果:

这次我们可以看到,
事件的处理就没有——
一次处理一个,依次处理,前者执行中,后者等待阻塞的特性了,
因为各个post的事件,
都有各自独立的线程去处理,
所以事件的处理运行是同时的、异步的;

小结

  • PostThread/MainThread缺点:
    一般执行在主线程,
    事件的个数,事件的耗时,
    都需要做比较严格的限制

  • BackgroundThread缺点:
    运行在后台线程,不占用主线程资源,
    PostThread/MainThread好那么一点,
    但是还是没有解决——
    多个(>= 2 个)事件时,
    一次处理一个,依次处理,
    前者执行,后者等待阻塞
    的问题,
    不适合事件中有耗时较长的任务

以上三种线程都是不适合跑耗时操作的;

Async adj.异步的;
核心:异步,同时,高效

  • 事件处理会在单独的线程中执行,
    主要用于在后台线程中执行耗时操作,
    每个事件会开启一个线程
    (程序初始化时,已经帮我们创建好一个线程池,
    每次POST一下框架都会去取一个线程来执行),
    但最好限制线程的数目
    (线程过多,CPU使用大,设备耗电快);

    每次POST一下框架都会去取一个线程来执行
    线程池中线程之间互相不干扰,可以同时运行

补充:

  • 另外一个需要注意的地方就是,
    EventBus.getDefault().register(this);系列的注册与反注册代码,
    onEvent()系列的接收函数是紧密绑定的;
    用时缺一不可,不用时存一不可,同生同灭;

    也就是说一个活动注册onEvent()系列的接收函数了,
    则必须用EventBus.getDefault().register(this);去注册,
    不然会报错;

    而一个活动它没有写onEvent()系列的接收函数,
    却用EventBus.getDefault().register(this);去注册了,
    同样也会报错!

使用技巧




参考资料:慕课网

上一篇 下一篇

猜你喜欢

热点阅读