Android——EventBus使用

1. EventBus序言

EventBus是一款针对Android优化的发布/订阅事件总线。主要功能是替代Intent、Handler、BroadCast在Fragment、Activity、Service、线程之间传递消息.优点是开销小,代码更优雅。以及将发送者和接收者解耦。EventBus在GitHub上的开源库地址,刚开始使用的可以看一下,GitHub上有最基本的使用方法。

EventBus优点

  1. 简化组件间的通信
    (1).对发送和接受事件解耦
    (2).可以在Activity,Fragment,和后台线程间执行
    (3).避免了复杂的和容易出错的依赖和生命周期问题
  2. 让你的代码更简洁
  3. 更快
  4. 更轻量(jar包小于50K)
  5. 拥有先进的功能比如线程分发,用户优先级等等

关于EventBus的使用主要遵循以下三步骤:

  • 自定义一个事件(事件是没有任何特殊要求的PLJO(Plain Old Java Object))

    public class MessageEvent { /* Additional fields if needed */ }
    
  • 准备订阅(订阅者)
    订阅者实现了事件处理方法(订阅者方法),这些方法将在事件发布时调用。Subscribe方法使用@subscribe 注解定义,对于EventBus 3,方法名可以自有选择

    // This method will be called when a MessageEvent is posted (in the UI thread for Toast)
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(MessageEvent event) {
        Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
    }
    // This method will be called when a SomeOtherEvent is posted
    @Subscribe
    public void handleSomethingElse(SomeOtherEvent event) {
        doSomethingWith(event);
    }
    

    Subscriber需要从“总线”来“注册”和“解注册”。Subscriber 只有在注册后才可以接收到事件。对于 Android ,在 Activity 和 Fragment 中通常应该根据生命周期注册。对于大多数情况,分别在 onStartonStop注册和解注册就可以

    @Override
    public void onStart() {
        super.onStart();
        EventBus.getDefault().register(this);
    }
    @Override
    public void onStop() {
        EventBus.getDefault().unregister(this);
        super.onStop();
    }
    
  • 发布事件
    代码中的任意部分都可以发布事件。所有已注册并且匹配该类型的 Subscriber(订阅者)都会收到该事件:

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

2 EventBus基本使用

EventBus最基本的引用如下:

implementation 'org.greenrobot:eventbus:3.1.1'

添加这个引用之后就可以使用EventBus了

简单使用示例

  • 简单框架搭建:创建两个Activity页面,设置Activity跳转

  • 新建一个类,FirstEvent

    public class FirstEvent {
    
        private String mMsg;
    
        public FirstEvent(String msg) {
            mMsg = msg;
        }
    
        public String getmMsg() {
            return mMsg;
        }
    }
    

    这个类很简单,构造时传进去一个字符串,然后可以通过getMsg()获取出来

  • 在要接收消息的页面注册EventBus
    我们要在MainActivity中接收发过来的消息,所以在MainActivity中注册消息。在onCreate()函数中注册EventBus,在onDestroy()函数中反注册

    public class MainActivity extends AppCompatActivity {
    
        private Button mButton;
        private TextView mTv;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            // 注册EventBus
            EventBus.getDefault().register(this);
            mButton = (Button) findViewById(R.id.btn_try);
            mTv = (TextView) findViewById(R.id.tv);
            mButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(getApplicationContext(), SecondActivity.class);
                    startActivity(intent);
                }
            });
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            EventBus.getDefault().unregister(this);
        }
    }
    
  • 发送消息,使用EventBus的Post方法来实现,发送过去即新建的类的实例。

    public class SecondActivity extends AppCompatActivity {
    
        private Button mBtnFirstEvent;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_second);
            mBtnFirstEvent = (Button) findViewById(R.id.btn_first_event);
            mBtnFirstEvent.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    EventBus.getDefault().post(new FirstEvent("FirstEvent btn Clicked"));
                }
            });
        }
    }
    
  • 接收消息
    接收消息,这里使用EventBus中常用的onEventMainThread()函数来接收消息。但是注意必须是要声明@Subscribe
    在MainActivity中重写onEventMainThread(FirstEvent event),参数就是我们自己定义的类,收到实例后,将其携带的消息取出,一方面Toast出去,一方面传到TextView中:

	@Subscribe
    public void onEventMainThread(FirstEvent event) {
        String msg = "onEventMainThread收到消息:" + event.getmMsg();
        Log.d("MainActivity", msg);
        mTv.setText(msg);
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    }

3. EventBus其他函数使用

前面简单演示了onEventMainThread()函数的接收,除此之外,还有:

  • onEvent
  • onEventMainThread
  • onEventBackgroundThead
  • onEventAsync

告知观察者事件发生时通过EventBus.post函数实现,这个过程叫做事件的发布,观察者被告知事件发生叫做事件的接收,是通过下面的订阅函数实现的

onEvent:使用onEvent作为订阅函数,那么该事件在哪个线程发布出来的,onEvent就会在这个线程中运行,也就是说发布事件和接收事件线程在同一个线程。使用这个方法时,在onEvent方法中不能执行耗时操作,如果执行耗时操作容易导致事件分发延迟。

onEventMainThread:如果使用onEventMainThread作为订阅函数,那么不论事件是在哪个线程中发布出来的,onEventMainThread都会在UI线程中执行,接收事件就会在UI线程中运行,这个在Android中是非常有用的,因为在Android中只能在UI线程中跟新UI,所以在onEvnetMainThread方法中是不能执行耗时操作的。

onEventBackground:如果使用onEventBackgrond作为订阅函数,那么如果事件是在UI线程中发布出来的,那么onEventBackground就会在子线程中运行,如果事件本来就是子线程中发布出来的,那么onEventBackground函数直接在该子线程中执行

onEventAsync:使用这个函数作为订阅函数,那么无论事件在哪个线程发布,都会创建新的子线程在执行onEventAsync

当发过来一个消息时,EventBus怎么知道要调哪个函数,就看哪个函数传进去的参数是这个类的实例,就调哪个。

3.1 订阅事件处理进阶

在EventBus3.0之后,可以自定义订阅事件处理方法名,可以在@Subscribe之后定义处理函数

@Subscribe(threadMode = ThreadMode.MAIN, priority = 2, sticky = true)
    public void eventMessageHander(FirstEvent event) {
        String msg = "eventMessageHandle收到消息:" + event.getmMsg();
        Log.d(TAG, msg);
    }

备注threadMode指线程模式,priority指事件的优先级,sticky是否是粘性事件

  • threadMode 线程模式有五种MAIN UI主线程、BACKGROUND 后台线程、POSTING 和发布者处在同一个线程、ASYNC 异步线程 、 MAIN_ORDERED ,UI主线程,但不会直接调用处理消息的方法,而是把事件加入到主线程的消息循环队列中执行。不写注解默认为POSTING模式
  • priority:和Boardcast接收者的优先级差不多,数越大优先级越高,一般0-100;
  • sticky:注册期间,所有粘性订户将立即获得之前发布的粘性事件。

3.2 普通事件与粘性事件

EventBus.getDefault().postSticky(new MessageEvent("发送粘性事件"));

普通事件的发送如上,其中EventBus是为了给已经存在的窗体传递信息,而且订阅者必须要注册且不能被注销了,否者接收不到消息。

粘性事件的发送如下:

EventBus.getDefault().postSticky(new MessageEvent("发送粘性事件"));

粘性事件发送后只要不取消就会一直存在。

粘性事件简单来说,就是发送事件之后再订阅该事件也能收到该事件。Android中也有这样的实例,就是Sticky Broadcast,即粘性广播。
EventBus也提供了这样的功能,不同的是EventBus会存储所有的Sticky事件,如果某个事件不再需要存储则需要手动进行移除。

3.3 移除事件

  • 普通事件删除
EventBus.getDefault().cancelEventDelivery(event);

备注:事件取消仅限于ThreadMode.PostThread下才可以使用

  • 粘性事件删除

    最近发布的粘性事件在其新订阅者注册后将会自动传递给新订阅者。但有时可能更方便手动检查粘性事件。有时我们也需要移除粘性事件,以免它在传递下去。

//指定粘性事件删除  
T stickyEvent = EventBus.getDefault().getStickyEvent(eventType);
  if (stickyEvent != null) {
        EventBus.getDefault().removeStickyEvent(stickyEvent);
      }
 //删除所有粘性事件 
 EventBus.getDefault().removeAllStickyEvents();

3.4 ProGuard

ProGuard 会混淆方法名甚至移除没有被调用的方法(dead code removal). 由于 Subscriber 方法一般情况下并不会被直接调用, 所以 ProGuard 假定它们是”无用的”. 因此当打开 ProGuard 的最小化开关之后, 必须明确指定保留这些 Subscriber 方法.
ProGuard配置文件添加下列规则:

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

猜你喜欢

转载自blog.csdn.net/weixin_43499030/article/details/90169503