中國廣東省深圳市望海路半島城邦三期
518067
+86 13113668890
<netkiller@msn.com>
php
$Id: book.xml 606 2013-05-29 09:52:58Z netkiller $html
版權 © 2018 Neo Chanjava
版權聲明python
轉載請與做者聯繫,轉載時請務必標明文章原始出處和做者信息及本聲明。android
|
|
|
|
2018-10git
個人系列文檔github
編程語言spring
目錄編程
47.1. 添加 EventBus 依賴到項目Gradle文件微信
http://greenrobot.org/eventbus
在EventBus中主要有如下三個成員:
Event:事件,能夠自定義爲任意對象,相似Message類的做用; Publisher:事件發佈者,能夠在任意線程、任意位置發佈Event,已發佈的Evnet則由EventBus進行分發; Subscriber:事件訂閱者,接收並處理事件,須要經過register(this)進行註冊,而在類銷燬時要使用unregister(this)方法解註冊。每一個Subscriber能夠定義一個或多個事件處理方法,其方法名能夠自定義,但須要添加@Subscribe的註解,並指明ThreadMode(不寫默認爲Posting)。
Gradle:
implementation 'org.greenrobot:eventbus:3.1.1'
完整的例子
apply plugin: 'com.android.application' android { compileSdkVersion 28 defaultConfig { applicationId "cn.netkiller.eventbus" minSdkVersion 26 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support.constraint:constraint-layout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' implementation 'org.greenrobot:eventbus:3.1.1' }
操做 EventBus 只需四個步驟
1. 註冊事件 EventBus.getDefault().register( this ); 2. 取消註冊 EventBus.getDefault().unregister( this ); 3. 訂閱事件 @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MessageEvent event) { Toast.makeText(this, event.message, Toast.LENGTH_SHORT).show(); } 4. 發送數據 EventBus.getDefault().post(new MessageEvent("Helloworld"));
package cn.netkiller.eventbus.pojo; public class MessageEvent { public final String message; public MessageEvent(String message) { this.message = message; } }
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:layout_marginEnd="8dp" android:text="Button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView" /> </android.support.constraint.ConstraintLayout>
package cn.netkiller.eventbus; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Toast; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import cn.netkiller.eventbus.pojo.MessageEvent; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); EventBus.getDefault().register(this); findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { EventBus.getDefault().post(new MessageEvent("Hello everyone!")); } }); } @Override protected void onDestroy() { super.onDestroy(); //取消註冊 , 防止Activity內存泄漏 EventBus.getDefault().unregister(this); } @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MessageEvent event) { Toast.makeText(this, event.message, Toast.LENGTH_SHORT).show(); } }
Sticky Events 粘性事件能夠理解爲Message作了持久化,直到Message被消費爲止。無需註冊便可發送Message。
下面的例子:在MainActivity發送事件,在StickyActivity裏註冊而且接收事件
A. MainActivity 發送事件: EventBus.getDefault().postSticky(new MessageEvent("http://www.netkiller.cn")); B. StickyActivity 接收事件 1. 註冊 EventBus.getDefault().register( this ); 2. 事件接收 @Subscribe(threadMode = ThreadMode.MAIN, sticky = true) public void onMessageEvent(MessageEvent event) { Toast.makeText(this, event.message, Toast.LENGTH_SHORT).show(); } 3. 取消註冊 EventBus.getDefault().unregister( this ) ;
Layout
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:layout_marginEnd="8dp" android:text="Button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView" /> </android.support.constraint.ConstraintLayout>
MainActivity
package cn.netkiller.eventbus; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Toast; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import cn.netkiller.eventbus.pojo.MessageEvent; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!")); startActivity(new Intent(MainActivity.this, StickyActivity.class)); } }); } }
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".StickyActivity"> </android.support.constraint.ConstraintLayout>
StickyActivity
package cn.netkiller.eventbus; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.Toast; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import cn.netkiller.eventbus.pojo.MessageEvent; public class StickyActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sticky); EventBus.getDefault().register(this); } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); } @Subscribe(threadMode = ThreadMode.MAIN, sticky = true) public void onMessageEvent(MessageEvent event) { Toast.makeText(this, event.message, Toast.LENGTH_SHORT).show(); } }
package cn.netkiller.eventbus.pojo; public class MessageEvent { public final String message; public MessageEvent(String message) { this.message = message; } }
MessageEvent stickyEvent = EventBus.getDefault().getStickyEvent(MessageEvent.class); // Better check that an event was actually posted before if(stickyEvent != null) { // "Consume" the sticky event EventBus.getDefault().removeStickyEvent(stickyEvent); // Now do something with it }
EventBus 有五種線程模型(ThreadMode)
Posting:直接在事件發佈者所在線程執行事件處理方法; Main:直接在主線程中執行事件處理方法(即UI線程),若是發佈事件的線程也是主線程,那麼事件處理方法會直接被調用,而且未避免ANR,該方法應避免進行耗時操做; MainOrdered:也是直接在主線程中執行事件處理方法,但與Main方式不一樣的是,不論發佈者所在線程是否是主線程,發佈的事件都會進入隊列按事件串行順序依次執行; BACKGROUND:事件處理方法將在後臺線程中被調用。若是發佈事件的線程不是主線程,那麼事件處理方法將直接在該線程中被調用。若是發佈事件的線程是主線程,那麼將使用一個單獨的後臺線程,該線程將按順序發送全部的事件。 Async:無論發佈者的線程是否是主線程,都會開啓一個新的線程來執行事件處理方法。若是事件處理方法的執行須要一些時間,例如網絡訪問,那麼就應該使用該模式。爲避免觸發大量的長時間運行的事件處理方法,EventBus使用了一個線程池來有效地重用已經完成調用訂閱者方法的線程以限制併發線程的數量。 後面會經過代碼展現五種ThreadMode的工做方式。
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".ThreadModeActivity"> <Button android:id="@+id/buttonSend" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:layout_marginEnd="8dp" android:text="Send" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/buttonThread" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:layout_marginEnd="8dp" android:text="Send Thread" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/buttonSend" /> </android.support.constraint.ConstraintLayout>
package cn.netkiller.eventbus; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; public class ThreadModeActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_thread_mode); EventBus.getDefault().register(this); findViewById(R.id.buttonSend).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.d("EventBus Thread : ", Thread.currentThread().getName()); EventBus.getDefault().post("http://www.netkiller.cn"); } }); findViewById(R.id.buttonThread).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new Thread(new Runnable() { @Override public void run() { Log.d("EventBus Thread : ", Thread.currentThread().getName()); EventBus.getDefault().post("http://www.netkiller.cn"); } }).start(); } }); } @Subscribe(threadMode = ThreadMode.POSTING) public void onMessageEventPostThread(String event) { Log.d("EventBus PostThread", "Message: " + event + " thread: " + Thread.currentThread().getName()); } @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEventMainThread(String event) { Log.d("EventBus MainThread", "Message: " + event + " thread: " + Thread.currentThread().getName()); } @Subscribe(threadMode = ThreadMode.MAIN_ORDERED) public void onEventMainOrdered(String event) { Log.d("EventBus MainOrdered", "Message: " + event + " thread:" + Thread.currentThread().getName()); } @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onMessageEventBackgroundThread(String event) { Log.d("EventBus BackgroundThread", "Message: " + event + " thread: " + Thread.currentThread().getName()); } @Subscribe(threadMode = ThreadMode.ASYNC) public void onMessageEventAsync(String event) { Log.d("EventBus Async", "Message: " + event + " thread: " + Thread.currentThread().getName()); } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); } }
在 main 線程中發佈消息
D/EventBus Thread :: main D/EventBus MainThread: Message: http://www.netkiller.cn thread: main D/EventBus PostThread: Message: http://www.netkiller.cn thread: main D/EventBus Async: Message: http://www.netkiller.cn thread: pool-1-thread-1 D/EventBus BackgroundThread: Message: http://www.netkiller.cn thread: pool-1-thread-2 D/EventBus MainOrdered: Message: http://www.netkiller.cn thread:main
在線程中發佈消息
D/EventBus Thread :: Thread-2 D/EventBus BackgroundThread: Message: http://www.netkiller.cn thread: Thread-2 D/EventBus PostThread: Message: http://www.netkiller.cn thread: Thread-2 D/EventBus Async: Message: http://www.netkiller.cn thread: pool-1-thread-2 D/EventBus MainOrdered: Message: http://www.netkiller.cn thread:main D/EventBus MainThread: Message: http://www.netkiller.cn thread: main
上面章節中的例子EventBus實例中採用默認方式
EventBus.getDefault().register(this);
這種方式的獲取到的EventBus的都是默認屬性,有時候並不能知足咱們的要求,這時候咱們能夠經過EventBusBuilder來個性化配置EventBus的屬性。
// 建立默認的EventBus對象,至關於EventBus.getDefault()。 EventBus installDefaultEventBus(): // 添加由EventBus「註釋預處理器生成的索引 EventBuilder addIndex(SubscriberInfoIndex index): // 默認狀況下,EventBus認爲事件類有層次結構(訂戶超類將被通知) EventBuilder eventInheritance(boolean eventInheritance): // 定義一個線程池用於處理後臺線程和異步線程分發事件 EventBuilder executorService(java.util.concurrent.ExecutorService executorService): // 設置忽略訂閱索引,即便事件已被設置索引,默認爲false EventBuilder ignoreGeneratedIndex(boolean ignoreGeneratedIndex): // 打印沒有訂閱消息,默認爲true EventBuilder logNoSubscriberMessages(boolean logNoSubscriberMessages): // 打印訂閱異常,默認true EventBuilder logSubscriberExceptions(boolean logSubscriberExceptions): // 設置發送的的事件在沒有訂閱者的狀況時,EventBus是否保持靜默,默認true EventBuilder sendNoSubscriberEvent(boolean sendNoSubscriberEvent): // 發送分發事件的異常,默認true EventBuilder sendSubscriberExceptionEvent(boolean sendSubscriberExceptionEvent): // 在3.0之前,接收處理事件的方法名以onEvent開頭,方法名稱驗證避免不是以此開頭,啓用嚴格的方法驗證(默認:false) EventBuilder strictMethodVerification(java.lang.Class<?> clazz) // 若是onEvent***方法出現異常,是否將此異常分發給訂閱者(默認:false) EventBuilder throwSubscriberException(boolean throwSubscriberException)
個人實例參考
EventBus eventBus = EventBus.builder().eventInheritance(true) .ignoreGeneratedIndex(false) .logNoSubscriberMessages(true) .logSubscriberExceptions(false) .sendNoSubscriberEvent(true) .sendSubscriberExceptionEvent(true) .throwSubscriberException(false) .strictMethodVerification(true) .build(); eventBus.register(this);
priority 數值越大優先級又高
// MainActivity @Subscribe(priority = 2) public void onMessageEvent(MessageEvent event) { Toast.makeText(this, event.message, Toast.LENGTH_SHORT).show(); } // SecondActivity @Subscribe(priority = 1) public void onMessageSecondEvent(MessageEvent event) { Toast.makeText(this, event.message, Toast.LENGTH_SHORT).show(); }
時間攔截,MainActivity 收到信息後調用 EventBus.getDefault().cancelEventDelivery(event); 以後全部訂閱將收不到信息。
// MainActivity @Subscribe(priority = 2) public void onMessageEvent(MessageEvent event) { Toast.makeText(this, event.message, Toast.LENGTH_SHORT).show(); EventBus.getDefault().cancelEventDelivery(event); } // SecondActivity @Subscribe(priority = 1) public void onMessageSecondEvent(MessageEvent event) { Toast.makeText(this, event.message, Toast.LENGTH_SHORT).show(); }
在 init() 中加入你的業務邏輯,根據須要,在特定的狀況下使用 throw new Exception("異常信息"); 拋出異常。異常會被 hrowableFailureEvent(ThrowableFailureEvent event) 捕獲到。
package cn.netkiller.eventbus; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Toast; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import org.greenrobot.eventbus.util.AsyncExecutor; import org.greenrobot.eventbus.util.ThrowableFailureEvent; import cn.netkiller.eventbus.pojo.MessageEvent; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); EventBus.getDefault().register(this); findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { AsyncExecutor.create().execute( new AsyncExecutor.RunnableEx() { @Override public void run() throws Exception { init(); EventBus.getDefault().post(new MessageEvent("Hello everyone!")); } } ); } }); } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); } @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MessageEvent event) { Toast.makeText(this, event.message, Toast.LENGTH_SHORT).show(); } public void init() throws Exception { // ... throw new Exception("實際發送異常"); } @Subscribe(threadMode = ThreadMode.MAIN) public void hrowableFailureEvent(ThrowableFailureEvent event) { Log.d("EventBus", "hrowableFailureEvent: " + event.getThrowable().getMessage()); Toast.makeText(this, event.getThrowable().getMessage(), Toast.LENGTH_SHORT).show(); } }