天天看點

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 源碼分析