EventBus 開源庫學習(一)

一、概念

EventBus是一款在 Android 開發(fā)中使用的發(fā)布-訂閱事件總線框架,基于觀察者模式,將事件的接收者和發(fā)送者解耦,簡化了組件之間的通信,使用簡單、效率高、體積小。

一句話:用于Android組件間通信的。

二、原理

image.png

三、簡單使用

  • 在app module的builde.gradle文件中導入依賴庫:
implementation 'org.greenrobot:eventbus:3.3.1'
  • 配置混淆
-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);
}

1、訂閱者EventBusService后臺注冊,前臺EventBusActivity 發(fā)送的數(shù)據。注冊以后一定要記得解注冊,否則會內存泄漏。onMsgEventReceived是接收消息的方法,該方法定義需要注意:

  • 該方法有且僅有一個參數(shù);
  • 必須用public修飾,不能使用static或者abstract;
  • 需要添加@Subscribe()注解;
public class EventBusService extends Service {
    private static final String TAG = "Test_EventBusService";

    @Override
    public void onCreate() {
        super.onCreate();
        //注冊數(shù)據監(jiān)聽
        EventBus.getDefault().register(this);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Subscribe
    public void onMsgEventReceived(String msg) {
        Log.i(TAG, "String msg: " + msg);
    }

    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true, priority = 1)
    public void onMsgEventReceived(MsgEvent event) {
        Log.i(TAG, "MsgEvent msg: " + event.getMsg());
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        //解注冊數(shù)據監(jiān)聽
        EventBus.getDefault().unregister(this);
    }
}

2、前臺Activity在按鈕點擊的時候發(fā)送信息到后臺Service。

public class EventBusActivity extends AppCompatActivity {
    private static final String TAG = "Test_EventBusActivity";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_event_bus);

        Button msg1Btn = findViewById(R.id.btn1);
        Button msg2Btn = findViewById(R.id.btn2);

        msg1Btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //發(fā)送數(shù)據給監(jiān)聽者
                EventBus.getDefault().post("msg1 - coming!?。?);
            }
        });

        msg2Btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //發(fā)送數(shù)據給監(jiān)聽者
                MsgEvent event = new MsgEvent("msg2 - coming?。。?);
                EventBus.getDefault().post(event);
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
}

3、MsgEvent數(shù)據類型。

public class MsgEvent {
    private String msg;

    public MsgEvent(String msg) {
        this.msg = msg;
    }

    public String getMsg() {
        return msg;
    }

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

    @Override
    public String toString() {
        return "MsgEvent{" +
                "msg='" + msg + '\'' +
                '}';
    }
}

4、運行結果


運行結果.png

四、Subscribe注解

Subscribe是EventBus自定義的注解,共有三個參數(shù)(可選):ThreadModeboolean sticky、int priority

    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true, priority = 1)
    public void onMsgEventReceived(MsgEvent event) {
        Toast.makeText(this, event.getMsg(), Toast.LENGTH_LONG).show();
    }

1、ThreadMode取值:

  • ThreadMode.POSTING:默認的線程模式,在哪個線程發(fā)送事件就在對應線程處理事件。避免了線程切換,效率高。

代碼測試:

#EventBusActivity 
msg1Btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //發(fā)送數(shù)據給監(jiān)聽者
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Log.i(TAG, "post thread: " + Thread.currentThread().getName());
                        EventBus.getDefault().post("msg1 - coming?。?!");
                    }
                }).start();

            }
        });

#EventBusService
@Subscribe
public void onMsgEventReceived(String msg) {
    Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());
    Log.i(TAG, "String msg: " + msg);
}

post的動作放到子線程中,結果如下,在哪個線程發(fā)送,就會在哪個線程執(zhí)行:

Thread.POSTING.png

  • ThreadMode.MAIN:如在主線程(UI線程)發(fā)送事件,則直接在主線程處理事件;如果在子線程發(fā)送事件,則先將事件入隊列,然后通過Handler切換到主線程,依次處理事件。

該模式下,在主線程(UI線程)發(fā)送事件,則直接在主線程處理事件,如果處理方法中有耗時操作就會堵塞進程。

代碼測試1:

#EventBusActivity 
msg1Btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //發(fā)送數(shù)據給監(jiān)聽者
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Log.i(TAG, "post thread: " + Thread.currentThread().getName());
                        EventBus.getDefault().post("msg1 - coming!??!");
                    }
                }).start();

            }
        });

#EventBusService
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMsgEventReceived(String msg) {
    Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());
    Log.i(TAG, "String msg: " + msg);
}

發(fā)送post代碼放到子線程中,處理事件代碼加上ThreadMode.MAIN注解參數(shù),結果如下,可以用在子線程處理耗時操作,然后返回值需要切回到主線程刷新UI的場景:

Thread.MAIN.png

代碼測試2:

#EventBusActivity 
msg1Btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //發(fā)送數(shù)據給監(jiān)聽者
                Log.i(TAG, "post thread: " + Thread.currentThread().getName());
                EventBus.getDefault().post("msg1 - coming!??!");
                Log.i(TAG, "post thread: " + Thread.currentThread().getName());
                EventBus.getDefault().post("msg1-1 - coming?。?!");
            }
        });

#EventBusService
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMsgEventReceived(String msg) {
    Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());
    Log.i(TAG, "String msg: " + msg);
    try {
        Thread.sleep(2 * 1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

發(fā)送post放在主線程并連續(xù)發(fā)送兩次,接收事件的函數(shù)加上耗時操作,運行結果如下,兩次post打印就相隔2s,第二次post需要等第一次事件接收處理完以后才能發(fā)出,所以主線程會阻塞:

Thread.MAIN_阻塞.png

同樣修改下發(fā)出post的代碼放到子線程后沒有這個問題,結果如下:

Thread.MAIN_子線程非阻塞.png

  • ThreadMode.MAIN_ORDERED:無論在那個線程發(fā)送事件,都先將事件入隊列,然后通過 Handler 切換到主線程,依次處理事件。
    代碼測試:
#EventBusActivity 
msg1Btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //發(fā)送數(shù)據給監(jiān)聽者
                Log.i(TAG, "post thread: " + Thread.currentThread().getName());
                EventBus.getDefault().post("msg1 - coming?。。?);
                Log.i(TAG, "post thread: " + Thread.currentThread().getName());
                EventBus.getDefault().post("msg1-1 - coming?。?!");
            }
        });

#EventBusService
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
public void onMsgEventReceived(String msg) {
    Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());
    Log.i(TAG, "String msg: " + msg);
    try {
        Thread.sleep(2 * 1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

代碼和ThreadMode.MAIN測試2一樣,只是將threadMode改為了MAIN_ORDERED,運行結果如下,兩次post可以連續(xù)發(fā)出:

MAIN_ORDERED.png

  • ThreadMode.BACKGROUND:如果在主線程發(fā)送事件,則先將事件入隊列,然后通過線程池依次處理事件;如果在子線程發(fā)送事件,則直接在發(fā)送事件的子線程處理事件。
    代碼測試1:
msg1Btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //發(fā)送數(shù)據給監(jiān)聽者
                Log.i(TAG, "post thread: " + Thread.currentThread().getName());
                EventBus.getDefault().post("msg1 - coming?。?!");
            }
        });

#EventBusService
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMsgEventReceived(String msg) {
    Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());
    Log.i(TAG, "String msg: " + msg);
}

運行結果如下,主線程發(fā)送事件,線程池依次處理事件:


ThreadMode.BACKGROUND.png

代碼測試2:

msg1Btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //發(fā)送數(shù)據給監(jiān)聽者
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Log.i(TAG, "post thread: " + Thread.currentThread().getName());
                        EventBus.getDefault().post("msg1 - coming?。?!");
                    }
                }).start();
            }
        });

#EventBusService
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMsgEventReceived(String msg) {
    Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());
    Log.i(TAG, "String msg: " + msg);
}

運行結果,子線程發(fā)送事件,則直接在發(fā)送事件的子線程處理事件:


ThreadMode.BACKGROUND_子線程.png
  • ThreadMode.ASYNC:無論在那個線程發(fā)送事件,都將事件入隊列,然后通過線程池處理。
    代碼測試1:
msg1Btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //發(fā)送數(shù)據給監(jiān)聽者
                Log.i(TAG, "post thread: " + Thread.currentThread().getName());
                EventBus.getDefault().post("msg1 - coming?。?!");
            }
        });

#EventBusService
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMsgEventReceived(String msg) {
    Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());
    Log.i(TAG, "String msg: " + msg);
}

運行結果,主線程發(fā)送,線程池處理:


ThreadMode.ASYNC_主線程.png

代碼測試2:

msg1Btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //發(fā)送數(shù)據給監(jiān)聽者
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Log.i(TAG, "post thread: " + Thread.currentThread().getName());
                        EventBus.getDefault().post("msg1 - coming?。?!");
                    }
                }).start();
            }
        });

#EventBusService
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMsgEventReceived(String msg) {
    Log.i(TAG, "onMsgEventReceived thread: " + Thread.currentThread().getName());
    Log.i(TAG, "String msg: " + msg);
}

運行結果,子線程發(fā)送,線程池處理:


ThreadMode.ASYNC_子線程.png

2、sticky:

sticky是否為粘性監(jiān)聽,boolean類型,默認值為false。正常我們都是先訂閱,才能接收到發(fā)出的事件,sticky的作用就是訂閱者可以先不進行注冊,事件先發(fā)出,再注冊訂閱者,同樣可以接收到事件,并進行處理。

3、priority:

priority是優(yōu)先級,int類型,默認值為0。值越大,優(yōu)先級越高,越優(yōu)先接收到事件。值得注意的是,只有在post事件和事件接收處理,處于同一個線程環(huán)境的時候,才有意義。

參考文章
EventBus詳解 (詳解 + 原理)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容