天天看点

EventBus 3.0 使用讲解EventBus

相关引用:

https://www.jianshu.com/p/a040955194fc

《Android进阶之光》第七章

EventBus

出现的原因

EventBus是一款针对Android优化的事件发布/订阅框架,为了简化并且高质量地在Activity、Fragment、Thread和Service之间通信,同时解决各组件之间高耦合的问题,同时仍能高效地通信。

传统的事件传递方式包括:Handler、BroadcastReceiver、Interface回调,相比之下EventBus的优点是代码简洁,使用简单,并将事件发布和 订阅充分解耦。

EventBus的组成部分

EventBus 3.0 使用讲解EventBus

三要素

Event:事件。又叫消息,其实就是一个对象,可以是网络请求返回的字符串,也可以是某个开关状态等等。事件类型EventType是指事件所属的Class。

事件分为一般事件和Sticky事件,相对于一般事件,Sticky事件不同之处在于,当事件发布后,再有订阅者开始订阅该类型事件,依然能收到该类型事件的最近一个Sticky事件。

Subscriber:事件订阅者。在EventBus 3.0以后,事件处理的方法可以随便取名,但是需要添加一个注解@Subscribe,并且要指定线程模式(默认为POSTING)

Publisher:事件发布者。可以在任意线程任意位置,通过post(MessageEvent)方法发送事件。可以自己实例化EventBus对象,但一般使用EventBus.getDefault()就可以。

EventBus是通过post函数传进去的类的实例来确定调用哪个订阅函数的,是哪个就调用哪个,如果有多个订阅函数呢,那么这些函数都会被调用!

四种ThreadMode

POSTING(默认):事件在哪个线程发布,订阅函数就会在哪个线程被调用,即发布时间和接收事件在同一个线程。此时订阅函数中尽量避免执行耗时操作,因为它会阻塞事件的传递,甚至有可能会引起ANR。

MAIN:订阅函数在UI线程中执行。注意要避免ANR

BACKGROUND:表示如果事件在UI线程中发布出来的,那么订阅函数onEvent就会在子线程中运行,如果事件本来就是在子线程中发布出来的,那么订阅函数直接在该子线程中执行。

ASYNC:无论事件在哪个线程发布,都会创建新的子线程来执行订阅函数。

使用步骤

首先当然要在gradlew文件添加EventBus的依赖啦:

implementation 'org.greenrobot:eventbus:3.1.1'
           
  1. 定义一个事件:
    public static class MessageEvent {
         /* Additional fields if needed */
     }
               
  2. 在事件订阅者类上:注册和注销您的订阅者。例如,在Android上,Activity和Fragment通常应根据其生命周期进行注册:
    @Override
     public void onStart(){
         super.onStart();
         EventBus.getDefault().register(this);
     }
     
     @Override
     public void onStop(){
         super.onStop();
     	// 不再使用时,请注销
         EventBus.getDefault().unregister(this);
     }
               
    声明并且注解你的订阅函数,注解中可选择指定的ThreadMode:
    @Subscribe(threadMode = ThreadMode.MAIN)
     public void onMessageEvent(MessageEvent event){
         /* Do something */
     };
               
  3. 发送事件:
    EventBus.getDefault().post(new MessageEvent());
               

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

Demo

创建事件MessageEvent类:

package com.example.wudongjiang.eventbusdemo;

public class MessageEvent {
    private String msg;
    public MessageEvent(String msg){
        this.msg = msg;
    }

    public String getMsg(){
        return this.msg;
    }

    public void setMsg(String msg){
        this.msg = msg;
    }
}
           

MainActivity:

package com.example.wudongjiang.eventbusdemo;

import android.content.Intent;
import android.os.Looper;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

public class MainActivity extends AppCompatActivity {

    private TextView mTv_show_text;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTv_show_text = findViewById(R.id.tv_show_text);
        findViewById(R.id.btn_register).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().register(MainActivity.this);
            }
        });
        findViewById(R.id.btn_go_to_second_activity).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this,SecondActivity.class));
            }
        });
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(MessageEvent event){
        boolean isMainThread = (Looper.myLooper() == getMainLooper());
        Toast.makeText(this,"是否运行在UI线程?"+isMainThread,Toast.LENGTH_SHORT).show();
        mTv_show_text.setText(event.getMsg());
    }

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

SecondActivity:

package com.example.wudongjiang.eventbusdemo;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

import org.greenrobot.eventbus.EventBus;

public class SecondActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        findViewById(R.id.btn_post_event).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().post(new MessageEvent("发送事件"));
            }
        });
    }
}
           

运行结果:

EventBus 3.0 使用讲解EventBus
EventBus 3.0 使用讲解EventBus
EventBus 3.0 使用讲解EventBus

EventBus的黏性事件

所谓黏性事件,就是在发送事件之后,再订阅该事件,也能收到,跟黏性广播类似。可修改上述代码验证。

MainActivity:

package com.example.wudongjiang.eventbusdemo;

import android.content.Intent;
import android.os.Looper;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

public class MainActivity extends AppCompatActivity {

    private TextView mTv_show_text;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTv_show_text = findViewById(R.id.tv_show_text);
        findViewById(R.id.btn_register).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().register(MainActivity.this);
            }
        });
        findViewById(R.id.btn_go_to_second_activity).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this, SecondActivity.class));
            }
        });
    }

    /**
     * 普通事件
     *
     * @param event
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(MessageEvent event) {
        boolean isMainThread = (Looper.myLooper() == getMainLooper());
        Toast.makeText(this, "是否运行在UI线程?" + isMainThread, Toast.LENGTH_SHORT).show();
        mTv_show_text.setText(event.getMsg());
    }

    @Subscribe(threadMode = ThreadMode.POSTING, sticky = true)
    public void onMessageStickyEvent(MessageEvent event) {
        boolean isMainThread = (Looper.myLooper() == getMainLooper());
        Toast.makeText(this, "是否运行在UI线程?" + isMainThread, Toast.LENGTH_SHORT).show();
        mTv_show_text.setText(event.getMsg());
    }

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

SecondActivity:

package com.example.wudongjiang.eventbusdemo;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

import org.greenrobot.eventbus.EventBus;

public class SecondActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        findViewById(R.id.btn_post_event).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().post(new MessageEvent("发送事件"));
            }
        });
        findViewById(R.id.btn_post_sticky_event).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().postSticky(new MessageEvent("发送黏性事件"));
            }
        });
    }
}
           

运行结果:

首先不再MainActivity点击注册事件,就直接跳转到SecondActivity,点击发送黏性事件。此时返回到MainActivity,是没有msg显示的,因为我们还没有点击订阅,然后点击MainActivity的注册事件,就有相应的Text显示了,说明接收成功:

EventBus 3.0 使用讲解EventBus
EventBus 3.0 使用讲解EventBus
EventBus 3.0 使用讲解EventBus

源码分析

EventBus 3.0 源码分析