【Android实战】EventBus 更少的代码 更好的体验

简介

事件总线库,极大地简化了 Activities, Fragments, Threads, Services等各组件之间的通讯。更少的代码,更好的体检
这里写图片描述
EventBus的github地址java

优势

  • 简化组件之间的通讯,对事件的发送者和接收者进行解耦;在Activity、Fragment、以及后台线程中运转良好;避免复杂和容易出错的依赖关系以及生命周期问题
  • 使你的代码更简单,代码可读性更好
  • 小(~ 50K的jar包)
  • 在安装量多达100,000,000+ 的应用中实践,表现优异
  • 独具特点的功能,如线程分发,优先级订阅等。

    这里写图片描述

项目实战


这里写图片描述

需求背景

  • 登陆、登出成功以后,涉及的相关页面要即时刷新登陆数据,作出相应的调整
  • 多个页面涉及比赛预定的状态,一个页面预定或者取消预定成功,要即时更新其它页面的比赛预定状态

步骤

部分概念相关的能够参考下面的相关介绍穿插理解git

一、首先须要定义消息类,该类能够不继承任何基类也不须要实现任何接口github

这里以LoginEvent(用户登陆退出场景) 和AppointmentStateEvent (见注释)为例来介绍web

public class OnEventBusInterface {
    public interface OnLoginListener {
        void onEventMainThread(LoginEvent event);
    }

    public interface OnTopicRefreshListener {
        void onEventMainThread(FollowTopicRefreshEvent event);
    }

    public interface OnAppointmentStateListener {
        void onEventMainThread(AppointmentStateEvent event);
    }

    public static class LoginEvent {
        private boolean hasLoginSucc;

        public LoginEvent(boolean loginSucc) {
            this.hasLoginSucc = loginSucc;
        }

        public boolean hasLoginSucc() {
            return hasLoginSucc;
        }

        public void setHasLoginSucc(boolean hasLoginSucc) {
            this.hasLoginSucc = hasLoginSucc;
        }
    }

    //FollowFragment刷新事件
    public static class FollowTopicRefreshEvent {
    }

    /** * 在比赛详情页 * 比赛未开始 * 从首页直播tab进入或者从球队详情页的比赛tab进入 * 在比赛未开始时,能够预定或者取消预定比赛,这个操做完成后再返回上面两个入口时,须要刷新预定状态 * 这里传入了matchId做为参数,目前没有用到,由于如今比赛的预定与否是存在本地数据库的 * 若是之后预定比赛的状态和用户绑定在服务器,那么可能就须要使用这个matchId了 * <p/> * 须要3个有关注状态的地方 互相通知最新的关注状态 * add By SuS */
    public static class AppointmentStateEvent {
        private String matchId;

        public AppointmentStateEvent(String matchId) {
            this.matchId = matchId;
        }

        public String getMatchId() {
            return matchId;
        }

        public void setMatchId(String matchId) {
            this.matchId = matchId;
        }
    }

二、在须要订阅事件的地方注册事件,在须要取消消息订阅的地方取消消息订阅数据库

public class BaseLoginActivity extends BaseActivity implements OnEventBusInterface.OnLoginListener{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EventBus.getDefault().register(this);//注册EventBus
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);//反注册EventBus
    }

    protected void onLoginSuccess(){
    }
    protected void onLoginOut(){
    }

    public void onEventMainThread(OnEventBusInterface.LoginEvent event){
        if(event.hasLoginSucc()){
            onLoginSuccess();
        }else{
            onLoginOut();
        }
    }

}
public class BaseLoginFragment extends BaseFragment implements IHandlerMessage,OnEventBusInterface.OnLoginListener,OnEventBusInterface.OnTopicRefreshListener,OnEventBusInterface.OnAppointmentStateListener {
    protected Handler handler;

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        handler = new CommonHandler<BaseLoginFragment>(this);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EventBus.getDefault().register(this);//注册EventBus
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);//反注册EventBus
    }

    @Override
    public void handlerCallback(Message msg) {
    }

    protected void showLoginWindow(){
        StormUtils2.startLoginActivity(getActivity());
    }

    protected void onLoginSuccess(){

    }

    protected void onLoginOut(){

    }

    protected void onFollowStatusChanged() {}

    protected void onAppointmentStateChanged(String matchId){

    }


    public void onEventMainThread(OnEventBusInterface.LoginEvent event){
        if(event.hasLoginSucc()){
            onLoginSuccess();
        }else{
            onLoginOut();
        }
    }

    public void onEventMainThread(OnEventBusInterface.FollowTopicRefreshEvent event){
        onFollowStatusChanged();
    }

    @Override
    public void onEventMainThread(OnEventBusInterface.AppointmentStateEvent event) {
        onAppointmentStateChanged(event.getMatchId());
    }
}

三、分发事件,即触发消息服务器

这里写图片描述

这里对BaseActivity小作解释:当经过插件化的方式加载暴风体育的时候,启动登陆,经过startActivityForResult的方式调用主版的登陆(之因此调用主版的登陆是由于主应用和以插件化方式加载的暴风体育第三方登陆(QQ,微信)的签名不一样),当登陆成功获取用户信息后,分发用户登陆成功的消息微信

代码很简洁,具体相关操做以下:ide

EventBus.getDefault().post(new OnEventBusInterface.LoginEvent(true));//登陆成功
EventBus.getDefault().post(new OnEventBusInterface.LoginEvent(false));//登出成功
EventBus.getDefault().post(new OnEventBusInterface.AppointmentStateEvent(String.valueOf(matchInfo.getId())));//比赛预定状态改变成功

四、消息处理svg

这里使用了最普通的方式,没有使用EventBus的注解模式,并且考虑到收到消息后的处理都是在主线程中完成,因此采用了onEventMainThread方法。函数

继承了BaseLoginActivity的Activity的相关处理:
这里写图片描述

继承了BaseLoginFragment的Fragment的相关处理:
这里写图片描述

注意

  • 在3.0以前,EventBus尚未使用注解方式。消息处理的方法也只能限定于onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,分别表明四种线程模型。而在3.0以后,消息处理的方法能够随便取名,可是须要添加一个注解@Subscribe,而且要指定线程模型(默认为PostThread)
  • 事件处理函数的访问权限必须为public,不然会报异常

相关代码以下:

public void onEventMainThread(OnEventBusInterface.LoginEvent event){
        if(event.hasLoginSucc()){
            onLoginSuccess();
        }else{
            onLoginOut();
        }
    }

    public void onEventMainThread(OnEventBusInterface.FollowTopicRefreshEvent event){
        onFollowStatusChanged();
    }

    @Override
    public void onEventMainThread(OnEventBusInterface.AppointmentStateEvent event) {
        onAppointmentStateChanged(event.getMatchId());
    }


这里写图片描述

相关介绍

线程模型

主要包括以下四种:
这里写图片描述

POSTING

  • 发布事件和接收事件在同一个线程
  • 避免执行耗时操做,不然会阻塞事件的传递,有可能会引发ANR
@Subscribe(threadMode = ThreadMode.POSTING) // ThreadMode is optional here
public void onMessage(MessageEvent event) {
    log(event.message);
}

MAIN

  • 不管事件从哪里发布,接收事件都在UI线程
  • 能够用来更新UI,可是不能处理耗时操做
// Called in Android UI's main thread
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessage(MessageEvent event) {
    textField.setText(event.message);
}

BACKGROUND:

  • 发布事件来自主线程,接收事件则在新的线程中运行;发布事件来自子线 程,接收事件也在该子线程完成
  • 禁止进行UI更新操做
// Called in the background thread
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessage(MessageEvent event){
    saveToDisk(event.message);
}

ASYNC

  • 不管事件从哪里发布,接收事件都在新的子线程
  • 禁止进行UI更新操做
// Called in a separate thread
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMessage(MessageEvent event){
    backend.send(event.message);
}

订阅优先级以及事件取消

尽管大多数状况下eventbus是不须要设置订阅的优先级和事件取消,可是某些特殊的场景可能派上用场。例如,当应用程序在前台,存在一个事件可能会触发一些用户界面相关逻辑,但当应用不可见时应该有不一样的反应

优先级设置:

  • 默认优先级是0,一样的线程分发模式,优先级更高的订阅者会先收到消息
  • 不一样线程模式的订阅者接收消息的顺序呢不受优先级影响
@Subscribe(priority = 1);
public void onEvent(MessageEvent event) {
…
}

事件取消

  • 事件取消通常都是被高优先级的订阅者调用
  • 严格限制在线程模式为POSTING的消息处理方法中
// Called in the same thread (default)
@Subscribe
public void onEvent(MessageEvent event){
// Process the event
…

EventBus.getDefault().cancelEventDelivery(event) ;
}

粘性事件

EventBus还支持发送黏性事件,就是在发送事件以后再订阅该事件也能收到该事件,可以收到订阅以前发送的消息。可是它只能收到最新的一次消息。

这里不作过多介绍,详情请参考Sticky Events

总结

  • 简单强大
  • 实战验证
  • 高性能
  • 基于API的简洁注解
  • 主线程和子线程都可进行消息发布和订阅
  • 事件以及订阅者继承特色
  • 零配置且可配

码字!排版!画图!终于写完了!


这里写图片描述