ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

EventBus 使用(全面分析,细节提醒)

2022-05-18 00:34:45  阅读:181  来源: 互联网

标签:提醒 onReceiveMsg message 细节 线程 事件 post EventBus


EventBus使用

概述

关于 EventBus 在开发中经常会选择使用它来进行模块间通信、解耦。平常使用这个库只是很浅显的操作三部曲,register,post,unregister。来达到开发目的。始终有种不明确,模糊的操作感。因此准备对EventBus进行一个深入,全面的理解,消除模糊,片面感,让以后在使用这个库的时候,有更好的掌握和使用。并记录下来,方便以后查阅。关于EventBus会分两章进行记录,本篇文章,是对EventBus的使用做一个全面的介绍,另一篇文章则会对EventBus库的源码进行分析,看看他的实现原理是什么样的。

关于

EventBus 是一个开源库,它利用发布/订阅者者模式来对项目进行解耦。它可以利用很少的代码,来实现多组件间通信。android的组件间通信,我们不由得会想到handler消息机制和广播机制,通过它们也可以进行通信,但是使用它们进行通信,代码量多,组件间容易产生耦合引用。关于EventBus的工作模式,这里引用一张官方图帮助理解。
image
上面这张图还是很好理解的,Publisher(发布者)通过post()方法,把Event事件发布出去,Subscriber(订阅者)在onEvent()方法中接收事件,可能现在你对Publisher,Subscriber, onEvent()这几个词还是不理解,没关系,别着急,放下看慢慢的你就懂了。

为什么会选择使用EventBus来做通信?

  • 简化了组件间交流的方式
  • 对事件通信双方进行解耦
  • 可以灵活方便的指定工作线程,通过ThreadMode
  • 速度快,性能好
  • 库比较小,不占内存
  • 使用这个库的app多,有权威性
  • 功能多,使用方便
    现在,我们就来体验EventBus的强大之处吧。

使用

导入项目

在build.gradle文件中导入EventBus库。

    implementation 'org.greenrobot:eventbus:3.1.1'

在项目的混淆文件中,加入EventBus 的混淆规则,这个千万别忘了,不然会出现,debug版本测试OK,release版本subscriber 收不到消息等诡异问题。

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

使用方式

EventBus库中最重要的三个点,分别是subscriber(订阅者),事件(消息),publisher(发布者)。主要理解这三者的关系即可。

subscriber ——> EventBus 的register方法,传入的object对象

事件(Event)——> EventBus 的post方法,传入的类型。

publisher(发布者)——> EventBus的post方法。


  1. 创建一个事件类型,消息事件类型可以是string,int等常见类,也可以是自己自定义一个事件类,方便管理。这边演示,创建了一个EventMessage事件类。
public class EventMessage {

    private int type;
    private String message;

    public EventMessage(int type, String message) {
        this.type = type;
        this.message = message;
    }

    @Override
    public String toString() {

        return "type="+type+"--message= "+message;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
  1. 在需要订阅事件的模块中,注册eventbus。
    MainActivity.java
@Override
    protected void onStart() {
        super.onStart();
        EventBus.getDefault().register(this);
    }

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

    }

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

关于EventBus的注册问题,说几点。

  1. 注册完了,在不用的时候千万别忘了unregister。
  2. 不能重复注册。注册之后,没有unregister,然后又注册了一次。
  3. register与unregister的时间根据实际需求来把控,官方的例子是在onStart()回调方法进行注册,onStop()回调方法进行unregister(),这边根据需求做了改动。

在需要接受事件的类中进行好register之后,需要在该类中创建一个方法来接收事件消息。

@Subscribe(threadMode = ThreadMode.MAIN)
    public void onReceiveMsg(EventMessage message) {
        Log.e(TAG, "onReceiveMsg: " + message.toString());
    }

创建的这个方法是有要求的。要求有如下几点。

  1. 该方法有且只有一个参数。
  2. 该方法必须是public修饰符修饰,不能用static关键字修饰,不能是抽象的(abstract)
  3. 该方法需要用@Subscribe注解进行修饰。

关于Subscribe注解的介绍,将在后面结合实例进行讲解。
3. 在需要发送事件的地方,调用EventBus的post(Object event),postSticky(Object event)来通知订阅者。
SecondActivity.java

private View.OnClickListener mSendListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.e(TAG, "onClick: " );
            EventMessage msg = new EventMessage(1,"Hello MainActivity");
            EventBus.getDefault().post(msg);
        }
    };

注意,该例子中,我使用了,EventBus.getDefault()方法,该方法会获取一个单例。所以才可以随时使用,如果不是用这种单例模式,需要想办法把订阅者(Subscriber)注册时用的EventBus的引用传给需要发送事件的模块中,简而言之就是Subscriber用的eventbus 和post方法需要的eventbus需要是同一个eventbus。

我们跑下代码测试一下。结果如下。
image

发现使我们想要的结果。那现在关于EventBus的基本使用,就明白了,主要就是三个部分,一个部分是Subscriber,需要在Subscriber类中进行register和unregister操作。一部分是在Subscriber中需要创建一个方法来接收事件信息,最后一部分就是在需要发送事件的环境使用post方法来发送事件信息。这三部分中所用到的eventBus实例得要是同一个实例。


@Subscribe 注解介绍

上面的接收事件的方法中,我们提到,必须要加入@Subscriber注解才可以,这其中的因果我们将在下篇文章进行分析,我们现在所要说的是Subscribe注解的用法。

@Subscribe是EventBus自定义的一种注解,他可接收三个参数。ThreadMode、boolean sticky、int priority。

所以上面的接收Event方法的代码,完整版的可以这样写:

@Subscribe(threadMode = ThreadMode.MAIN,sticky = true,priority = 1)
    public void onReceiveMsg(EventMessage message) {
        Log.e(TAG, "onReceiveMsg: " + message.toString());
    }

这三个参数可以根据需要选择是否使用。

threadMode 是用来决定onReceiveMsg将在哪种线程环境下被调用。EvenBus一共有5种Thread mode。

POSTING :这是EventBus的默认模式,表示post事件是什么线程,onReceiveMsg接收事件方法就在同样的线程环境中执行代码。例如:

订阅处

@Subscribe()
    public void onReceiveMsg(EventMessage message) {
        Log.e(TAG, "onReceiveMsg: " + message.toString());
        Log.e(TAG, "onReceiveMsg: current thread name ="+Thread.currentThread().getName() );
    }

发布处

private View.OnClickListener mSendListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.e(TAG, "onClick: " );
            new Thread(new Runnable() {
                @Override
                public void run() {
                    String name = Thread.currentThread().getName();
                    Log.e(TAG, "run: thread  name = "+name );
                    EventMessage msg = new EventMessage(1,"Hello MainActivity");
                    EventBus.getDefault().post(msg);

                }
            }).start();
        }
    };

结果
image

我们看到,他们所处的线程环境是一样的。

这种模式,适合使用在执行简单任务的情况下,不需要复杂运算,因为这种模式不需要做线程切换的判断逻辑,直接分发至相同的线程环境,速度快,耗时少。
MAIN:关于MAIN 这种线程模式,可以和MAIN_ORDERED一起讨论,他们都是表示,无论事件发布在什么线程,事件接收都是在主线程中执行。那MAIN模式和MAIN_ORDERED模式的区别在哪里呢?

区别在于,对于MAIN 模式,如果事件发布者post事件也是在主线程的话,会阻塞post事件所在的线程。意思就是连续post多个事件,如果接收事件方法执行完,才能post下一个事件。

post(1) ——> onReceiveMsg(1) ———>post(2)———>onReceiveMsg(2)———>post(3)————>onReceiveMsg(3)

如果事件发布者post事件不在主线程的话,连续post多个事件,同是在主线程是接收事件是耗时操作的话,执行的流程会是这样的。是非阻塞的(non-blocking)

post(1)——>post(2)——>psot(3)———>onReceiveMsg(3)

或者

post(1)——>post(2)——>psot(3)———>onReceiveMsg(2)——>onReceiveMsg(3)

那对于MAIN_ORDERED模式无论事件发布者post在什么线程环境,他的执行流程是都非阻塞的(non-blocking),和MAIN模式 下,post环境不是主线程的执行流程一样。

BACKGROUND:该模式下的时间发布者post线程环境与事件接收onReceiveMsg方法的线程环境关系如下:

post发布环境是主线程的话,事件接收处理的环境是一个子线程。

post发布环境是子线程的话,事件接收处理环境和post发布环境一样。

ASYNC:该模式表示,无论post环境是什么线程,事件接收处理环境都是子线程。

以上就是EventBus五种线程模式的解读。上面说了Subscriber注解的ThreadMode参数的含义。接着我们说另外两种参数的含义。

sticky

sticky是一个boolean型的参数,默认值是false,表示不启用sticky特性。那么sticky特性是什么呢?我们之前说的EventBus事件传递的例子的时候,我们都是先对订阅者(Subscriber)进行先注册的,然后再post事件的。那sticky的作用是在先post事件,后对订阅者注册这种开发场景的支持的。
举个例子:

 private View.OnClickListener mGoListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.e(TAG, "onClick: post");
            EventMessage message = new EventMessage(233, "post message before");
            EventBus.getDefault().postSticky(message);
        }
    };

    private View.OnClickListener mRegisterListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.e(TAG, "onClick: start register" );
            EventBus.getDefault().register(MainActivity.this);
        }
    };

我首先会点击触发go事件,通过postSticky()发送一个事件,然后再通过点击触发register事件,对Subscriber进行注册。结果log如下:

2018-12-08 10:40:54.444 9129-9129/com.example.yumryang.eventbusdemo E/MainActivity: onClick: post
2018-12-08 10:40:57.365 9129-9129/com.example.yumryang.eventbusdemo E/MainActivity: onClick: start register
2018-12-08 10:40:57.369 9129-9129/com.example.yumryang.eventbusdemo E/MainActivity: onReceiveMsg: type=233--message= post message before
2018-12-08 10:40:57.369 9129-9129/com.example.yumryang.eventbusdemo E/MainActivity: onReceiveMsg: current thread name =main

priority

该参数是int型,默认值是0,比较好理解,就像他的参数名所表示的那样,优先级。值越高,越先接收到事件,不过这里要注意一个问题,那就是优先级的比较前提是在post事件发布,onReceiveMsg事件接收处理这两方的线程环境相同的前提下,才有意义。同是与priority相配合使用的一个方法是cancelEventDelivery.关于它们的使用就不在演示,比较简单。

结尾

EventBus的入门篇,大致就说这些, 可能还有些注意问题,暂时没想起来,等下一篇,关于EventBus源码分析的时候到时候遇到了,再提出来吧。


第二篇文章出来啦!
EventBus源码分析,看这一篇就够了!

本文转自EventBus 使用(全面分析,细节提醒)

标签:提醒,onReceiveMsg,message,细节,线程,事件,post,EventBus
来源: https://www.cnblogs.com/sishuiliuyun/p/16283018.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有