EventBus
1、前言
(一)、做用
一、Android 事件發佈 / 訂閱框架
二、事件傳遞既能夠用於Android 四大組件間的通訊
三、用戶異步線程和主線程間通訊的時候進行聯繫的工具
(二)、意義
經過框架解耦事件的 發佈者 和訂閱者 ,進而簡化Android 事件傳遞
(三)、優勢
代碼簡潔,使用簡單,並將事件發佈和訂閱充分解耦
(四)、傳統的事件傳遞方法
a、handler
b、BroadcastReceiver
c、接口回調
傳統事件傳遞的缺陷:
代碼量臃腫、繁瑣、複雜
傳統事件傳遞之handler
handler 機制工做原理
ps:Android 中的主線程 :ActivityThread 類——Ui線程
經過這個類建立的Looper 和 Handler 就能夠進行消息的傳遞了
思考1:子線程是否能夠建立handler對象?
答: 子線程直接建立handler對象會報 缺乏Looper對象的錯誤。進行三個步驟建立handler :
一、調用Looper的prepare()方法建立當前線程的Looper
二、以後建立當前線程的Handler()
三、在建立完Handler()後要經過Looper.loop()開啓Looper消息隊列的循環
解析:在Android異步消息處理機制中,handler就是用來處理消息的,並進行消息的發送,和處理在handleMessage。
發出、通過處理的消息最後都會回到handler這個方法中來執行。
Looper 每一個線程中MessageQueue的管家,負責消息隊列的運做。Looper內部死循環不斷的從MessageQueue中獲取消息,
有消息就取出並返回給handleMessage去進行處理。因此也就是說單單僅有一個handler是沒法進行消息的處理工做的,由於沒有Looper 沒法獲取MessageQueue 中的消息。
也就是說須要handler發送消息後經過Looper接收消息,放到MessageQueue中進行輪詢操做。最後looper會將Message 返回給handler,調用handleMessage 方法進行異步消息的處理操做。
思考2:handler 在Activity中進行消息的傳遞有幾種形式?
實例代碼一 形式:
/**
* 利用handler,在Ui 主線程中發送消息,在work子線程執行耗時操做
*/
public class HandlerSendMessageActivity extends Activity {
public Button btn1;
Handler handler;//主線程handler
public TextView textview;
@Override
public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
setContentView(R.layout.butterknife_layout);
textview = findViewById(R.id.textview_1);
btn1 = findViewById(R.id.button_1);
btn1.setText("Ui->Work");
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//主線程發送消息給子線程去處理須要耗時的操做
Message msg = handler.obtainMessage();
msg.arg1 = 1;
msg.obj = "obj 消息";
handler.sendMessage(msg);
System.out.println(Thread.currentThread().getName());
}
});
new MyThread().start();
}
class MyThread extends Thread {
@Override
public void run() {
//子線程建立handler以前必定要首先建立looper 經過Looper.prepare();
Looper.prepare();
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
System.out.println(Thread.currentThread().getName());
super.handleMessage(msg);
}
};
Looper.loop();
super.run();
}
}
}
實例代碼二 形式:
/**
* 利用handler,在子線程發送消息,而後在主線程中獲取並執行
*/
public class HandlerGetMessageActivity extends Activity {
Button btn1;
//一、主線程定義handler 並重現handleMessage()
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
System.out.println(Thread.currentThread().getName());
System.out.println("消息-->" + msg.arg1 + "-" + msg.obj);
super.handleMessage(msg);
}
};
@Override
public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
setContentView(R.layout.butterknife_layout);
btn1 = findViewById(R.id.button_1);
btn1.setText("Work-->Ui");
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//二、開啓一個子線程在run()方法中發送消息給主線程處理
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Message msg = handler.obtainMessage();
msg.arg1 = 1;
msg.obj = "obj 消息";
handler.sendMessage(msg);
System.out.println(Thread.currentThread().getName());
}
});
thread.start();
}
});
}
}
2、EventBus框架基本用法
(一)eventbus 流程圖
event ———event————Subscriber
Publisher ——————>Event Bus — |
(發佈器) post() ———event————Subscriber
流程:發佈器 經過post()方法 把event 發佈到 event bus 總線當中 ,eventbus總線中根據 event 事件類型 匹配給相應的訂閱者
ps:注意只有註冊了事件才能收到event 發送的請求;同時反註冊能夠清理須要的eventbus請求
(二)eventbus 使用方法
一、導入:
implementation 'org.greenrobot:eventbus:3.0.0'
二、定義自定義事件event類型
public class MyBusEvent{
public final String message;
public MyBusEvent(String message) {
this.message = message;
}
}
三、建立訂閱者-經過註解
//訂閱者必定要帶上@Subscribe註解,eventbus以後的訂閱者方法名能夠隨意
@Subscribe(定義這個方法完成的線程級別),不用考慮線程問題拋出的異常
@Subscribe(threadMode = ThreadMode.MAIN) //表示onMessageEvent()在主線程中完成
public void onMessageEvent(MyBusEvent event) {
System.out.println();
}
}
四、註冊與反註冊事件
@Override
protected void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
protected void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
ps:註冊與反註冊 若是在Activity 或是fragment 這類組件,儘可能與它的生命週期綁定在一塊兒
五、發送事件 -無位置限制-主/子線程都可以發送事件
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//主線程發送消息給子線程去處理須要耗時的操做
Message msg = handler.obtainMessage();
msg.arg1 = 1;
msg.obj = "obj 消息";
handler.sendMessage(msg);
//將自定義的事件類型,做爲參數傳遞給post()函數
EventBus.getDefault().post(new MyBusEvent("test fot eventbus"));
}
});
ps:全部註冊、訂閱這個事件的訂閱者都可以匹配接收的這個事件xxx
3、EventBus框架的對象構建 和線程調度
EventBus 的實例化均帶有EventBus.getDefault() 方法,因此以此爲入口:
簡單來講:EventBus就是一個單例模式建立並用構建者模式Build內部類構建的對象
EventBus.getDefault():雙檢查機制的單例模式
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
思考:單例模式構造函數通常都是private修飾的,可是eventBus的構造模式是public 修飾的,這個緣由是?
publicEventBus() {
this(DEFAULT_BUILDER);
}
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
解析:EventBus在代碼中並非只有一條 總線,還有其餘的總線。訂閱者能夠註冊到不一樣的EventBus上,經過不一樣的EventBus發送數據。不一樣的EventBus發送的數據是相互隔離開的,訂閱者只會收到註冊在該線程上的數據。經過上面DEFAULT_BUILDER 對象的初始化能夠發現EventBus構建對象是經過構建者模式 Builde內部類 進行構建的。
EventBus 的對象構建
private final ThreadLocal<PostingThreadState> currentPostingThreadState= new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
ps:ThreadLocal是 線程內部的數據存儲類 ,經過它能夠在指定的線程中存儲數據,也只有在指定的線程中能夠獲取到數據。其餘線程沒法獲取到
EventBus(EventBusBuilder builder) {
subscriptionsByEventType = new HashMap<>();
//以event 爲key,以subscribe爲value值
ps:能夠經過subscriptionsByEventType這個HashMap找到對應的訂閱者
typesBySubscriber = new HashMap<>();
//以subscribe爲key,以event爲value
ps:當進行註冊和反註冊事件的時候都會在這個typesBySubscriber HashMap中操做
stickyEvents = new ConcurrentHashMap<>();
//粘性事件,當event發送出去後再註冊粘性事件的話,這個粘性事件也能收到以前發送的event事件
ps:ConcurrentHashMap是一個併發的HashMap
思考 :什麼是post? 答: 負責線程間調度
三個比較重要的成員變量的初始化 mainThreadPoster、backgroundPoster、asyncPoster
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0; //eventbus生成的索引
//對已經設定好註解的@Subscribe的Method方法的找尋器
//經過這個方法找尋設定好註解的方法
subscriberMethodFinder= new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
logSubscriberExceptions = builder.logSubscriberExceptions; //發生異常是否進行異常信息的打印
logNoSubscriberMessages = builder.logNoSubscriberMessages;//沒有訂閱者訂閱該事件的時候是否打印日誌
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;//當調用事件處理函數時若發生異常是否須要發送這個事件
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;//當沒有事件處理的時候是否對事件處理髮送sendNoSubscriberEvent
throwSubscriberException = builder.throwSubscriberException;//是否須要拋出異常
eventInheritance = builder.eventInheritance; //與event有繼承關係的是否都須要發送
executorService = builder.executorService;
}
下面看一下eventBus 最核心的三個線程間調度的方法:
(1) 、mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
final class HandlerPoster extends Handler因此可知其實際上就是個handler 具柄
//存放即將執行的post的隊列
private final PendingPostQueue queue;
//post這個事件最大的所能在handler當中handleMessage()所存在的最大時間值 max值
private final int maxMillisInsideHandleMessage;
//標着者handler是否運行起來
private boolean handlerActive;
在handleMessage()方法的任務,首先開啓while一個循環,從隊列中不停的獲取數據後,調用invokeSubscriber()方法進行事件的分發
eventBus.invokeSubscriber(pendingPost);
//而後,每分發完一次事件都會對比下時間,判斷這個method的時間timeInMethod 是否大於等於maxMillisInsideHandleMessage這個最大值時間,若小於就跳出循環,來繼續下面的操做
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage)
handleMessage() 循環的源碼:
while (true) {
//從前面定義好的queue隊列中經過poll方法拉取須要的PendingPost對象
pendingPost實際上就是一個維護着能夠複用的對象的複用池
PendingPost pendingPost = queue.poll();
ps:PendingPost是一個arrayList,內部有兩個核心方法:獲取pendingPost:obtainPendingPost() 和
回收pendingPost:releasePendingPost()
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;//設置標誌位爲false,說明handler尚未運行
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
(2) 、backgroundPoster = new BackgroundPoster(this);
final class BackgroundPoster implements Runnable
@Override
public void run() {
try {
try {
//在while循環中不斷的從隊列中獲取消息,一樣經過相似的eventBus.invokeSubscriber 進行事件的分發
ps:注意這裏是有一個限定條件,直到取完池中因此的爲止
while (true) {
PendingPost pendingPost =queue.poll(1000);
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
executorRunning = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
}
} catch (InterruptedException e) {
Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
(3) 、asyncPoster = new AsyncPoster(this);
AsyncPoster implements Runnable ,區別與BackgroundPoster:
只獲取隊列中一個PendingPost,而後進行invokeSubscriber()事件的分發
@Override
public void run() {
PendingPost pendingPost = queue.poll();
if(pendingPost == null) {
throw new IllegalStateException("No pending post available");
}
eventBus.invokeSubscriber(pendingPost);
}
4、EventBus框架的subscribe註解
@Documented //指定爲是一個JavaDocument 文檔
@Retention(RetentionPolicy.RUNTIME) //指定能夠在運行時有效
@Target({ElementType.METHOD}) //指定用來描述方法
public @interface Subscribe{
//線程模式
ThreadModethreadMode() default ThreadMode.POSTING;
boolean sticky() default false; //判斷是否爲粘性事件
int priority() default 0;
}
ThreadMode 枚舉類:
POSTING
/ 默認的線程模式;在執行post操做的時候線程會直接調用訂閱者的事件方法
MAIN
/ 在主線程中執行;當發佈線程是在主線程能夠直接調用該訂閱者的方法;不然須要經過handlePost發送消息
BACKGROUND--backgroundPost進行調度(全部隊列)
/ 後臺線程;表示在後臺線程中執行相應的方法,若是發佈線程不是在主線程中,不能夠直接調用訂閱者函數,必須啓動惟一的後臺線程進行處理,後臺線程是惟一的,當事件發送post超過一個的時候會被放置在這裏依次處理
ASYNC —asyncPoster 每次只會從隊列裏獲取一個因此不存在卡頓
/ 不論方法線程是在哪一個線程都會使用一個空線程進行處理;Async全部的線程都相互獨立,不會出現線程卡頓現象
粘性事件
事件消費者在事件發佈以後才註冊的也能接收到該事件的特殊類型
Sticky Broadcast 粘性廣播-傳統
粘性廣播存在的意義:
在正常狀況下,若是發送者發送了某個廣播,而接受者在這個廣播發送廣播以後才註冊廣播接收者的話,那麼廣播接收者是沒法接受到剛纔的廣播的。
引入以後:
當接收者註冊完以後,還能夠接收到剛纔發出的廣播
在廣播發射結束後保存剛剛發送的廣播
區別於傳統:
Android 的 EventBus會存儲全部的Sticky事件,也就是說某個事件不須要的時候就進行手動的移除操做
5、EventBus框架的register訂閱者
每新建一個eventbus總線,它的發佈和訂閱事件都是相互隔離的
舉例:建立一個eventbus對象,在這個對象中經過他發佈事件;而後又建立一個eventBus對象,在這個eventbus對象中,訂閱者是不會收到前一個eventbus所發生的事件的
public void register(Object subscriber) {
//經過反射機制 獲取到訂閱者的class對象
Class<?> subscriberClass = subscriber.getClass();
//register的核心方法——findSubscriberMethods
經過subscriberMethodFinder找尋器的findSubscriberMethods訂閱對象class找到訂閱方法的集合,返回一個訂閱方法的集合
List<SubscriberMethod> subscriberMethods =
//完成註冊訂閱的第一步:
subscriberMethodFinder.findSubscriberMethods(subscriberClass);
//遍歷訂閱好的方法集合 ,進行每一個方法的訂閱操做
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
findSubscriberMethods():
//SubscriberMethod 類型的 List
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
SubscriberMethod:EventBus 總的包裝類
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//一、從方法緩存池中查找是否已經有了這個方法,若是有的話就把這個集合返回
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
//索引的判斷(默認是false) ,因此會進入findUsingInfo()方法
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
//獲取到訂閱方法的集合
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
//將subscriberMethods 存儲到METHOD_CAHCE當中
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
findUsingInfo():
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//一、獲取到FindState對象 ,找到訂閱過的方法和其狀態,若是沒有就new 新建一個FindState對象
FindState findState = prepareFindState();
...
ps:FindState(){
定義:
//保存全部訂閱方法的ArrayList
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
//保存事件類型爲key ,訂閱類型爲value的HashMap
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
// 訂閱方法爲Methodkey,訂閱者的class對象爲value
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
}
//找到FindState對象的state狀態
private FindState prepareFindState() {
//從Find state對象池中查找
synchronized (FIND_STATE_POOL) {
//遍歷對象池查找須要的 state對象
for (int i = 0; i < POOL_SIZE; i++) {
FindState state = FIND_STATE_POOL[i];
if (state != null) {
//已經找到了可用的複用的State,這時候將該位置清空,爲了之後能夠繼續複用它,並返回這個狀態給FindState()函數
FIND_STATE_POOL[i] = null;
return state;
}
}
}
//當遍歷完整個對象池尚未找到須要的state的時候調用new FindState()建立一個新的state
return new FindState();
}
...
...
findState.initForSubscriber(subscriberClass);
...
//在while 循環結尾 每一次循環以後都會經過moveToSuperclass()進行下一次的循環
while (findState.clazz != null) {
//getSubscriberInfo()函數獲取到FindState訂閱者的信息
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
//首先得到 findState對象當中的訂閱方法的集合
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
//經過for循環進行 訂閱方法的遍歷
for (SubscriberMethod subscriberMethod : array) {
//訂閱方法過濾操做—> 返回true ,訂閱好的方法,以及訂閱方法的事件類型都是符合它的準則的
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
//將訂閱的方法添加到findState的arrayList中,也就是subscriberMethods
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
//若是getSubscriberMethods() 返回爲null 空,則進入下面
ps:getSubscriberMethods()默認狀況下通常都是null
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
findState.checkAdd():
boolean checkAdd(Method method, Class<?> eventType) {
//以eventType事件類型爲key,以method爲value
//一、anyMethodByEventType.put()會返回以前的方法
Object existing = anyMethodByEventType.put(eventType, method);
if (existing == null) {
return true;
} else {
ps:在eventbus中 有一種特色:
一個訂閱者包括訂閱者的全部的父類和子類,不會有多個方法,相同的所有去接收同一個事件;
if (existing instanceof Method) {
if (!checkAddWithMethodSignature((Method) existing, eventType)) {
throw new IllegalStateException();
}
anyMethodByEventType.put(eventType, this);
}
但有可能子類有可能會訂閱該事件,同時它的父類也會訂閱該事件的時候,會調用checkAddWithMethodSignature()來根據方法的簽名來檢查
return checkAddWithMethodSignature(method, eventType);
}
}
checkAddWithMethodSignature():根據方法的簽名來檢查過濾
private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(method.getName());
methodKeyBuilder.append('>').append(eventType.getName());
String methodKey = methodKeyBuilder.toString();
Class<?> methodClass = method.getDeclaringClass();
//以方法爲key,以訂閱好的類的class對象爲value;
//調用put方法()也會和以前同樣會返回以前的訂閱的class對象,而後根據class對象進行下一步操做
Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
//若是這個class對象不存在 ,或者是這個值是method 對象的父類的話就會返回true
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
return true;
} else {
//若是不是的話 ,或是class對象是空,就會把methodKey做爲key 添加到subscriberClassByMethodKey 這個HashMap中
ps:這個時候並無put內容進緩存;由於put的值是methodClassOld是之前的class
put()方法目的是revery:不要出現一個訂閱者有多個相同方法,訂閱同一個事件,若是有的話就把之前的這個class放到hashMap中去覆蓋
subscriberClassByMethodKey.put(methodKey, methodClassOld);
return false;
}
}
findUsingReflectionInSingleClass():經過這個方法找到哪些是訂閱者訂閱好的方法 或是 事件
private void findUsingReflectionInSingleClass(FindState findState) {
…
//一、經過反射的getDeclaredMethods() 獲取到訂閱者全部的方法
methods = findState.clazz.getDeclaredMethods();
…
//二、對前面獲取到的方法進行依次的遍歷
for (Method method : methods) {
//三、獲取到方法的修飾符 ,而後用這個修飾符進行判斷
int modifiers = method.getModifiers();
//四、判斷這個方法是不是public 以及該方法的修飾符是否能夠忽略
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0){
//五、getParameterTypes()獲取方法的參數
Class<?>[] parameterTypes = method.getParameterTypes();
//六、進行方法參數的判斷是否等於1
ps:eventbus中只容許訂閱方法後面的訂閱事件是1個,因此經過方法參數長度的判斷過濾出參數只有1哥的方法
if (parameterTypes.length == 1) {
//七、調用getAnnotation()方法獲取Subscribe對象,用來過濾出只被@Subscribe修飾過的方法
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
…
//八、被subscribeAnnotation過濾好的方法的threadMode()方法獲取到相應的線程模式
ThreadMode threadMode = subscribeAnnotation.threadMode();
//九、根據不一樣的線程模式 進行不一樣的線程調度操做
SubscriberMethod封裝的eventbus使用時候所須要的對象添加到FindState 存儲方法的集合當中
findState.subscriberMethods.add(
new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
…
}
getMethodsAndRelease
():進行返回和釋放資源的操做
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
//進行資源回收
findState.recycle();
...
}
6、EventBus框架的subscribe 觀察者
目標:根據獲取到方法的集合單個方法的獲取工做
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods =
//完成註冊訂閱的第一步:
subscriberMethodFinder.findSubscriberMethods(subscriberClass);
//下面的目標是:遍歷訂閱好的方法集合 ,進行每一個方法的訂閱操做
//創建同步代碼塊
synchronized (this) {
//遍歷獲取到的方法集合——
ps:在上一版本中 是經過 獲取subscriberMethods的迭代器 ,而後while循環不斷的遍歷這個迭代器(迭代器.hasNext())
//加強for循環 不斷遍歷獲取到每個訂閱方法
for (SubscriberMethod subscriberMethod : subscriberMethods) {
//完成訂閱的第二步:調用該方法完成訂閱
ps:
parameter:訂閱者-subscriber
parameter:訂閱方法-subscriberMethod
subscribe(subscriber, subscriberMethod);
}
}
}
subscribe():
主體流程:
- 一、首先判斷是否有註冊過該事件;有註冊過拋出異常
- 二、按照優先級順序加入到 subscriptionsByEventType的 value的List中;經過這個HashMap 找到該事件的訂閱者、
- 訂閱的方法和參數 等等
- 三、再添加到typesBySubscriber的value的List中;經過這個HashMap可使訂閱者找到該訂閱者訂閱的全部事件
- 四、判斷是不是粘性事件、是否有繼承關係
- 五、調用checkPostStickyEventToSubscription進行事件的的分發
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//首先獲取訂閱方法的 事件類型 eventType屬性
Class<?> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
ps:Subscription內部封裝了 subscriber訂閱者 和 subscriberMethod 訂閱方法;
而subscriberMethod又封裝了訂閱的方法,線程模式,事件類型,優先級,是不是粘性事件等屬性。
因此在這裏能夠看出Subscription 是一個更大的封裝類而已
//subscriptionsByEventType這個HashMap的key就是eventType,而value就是subscriptions
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
ps:CopyOnWriteArrayList 是一個能夠併發讀寫的arrayList
//若是subscriptions 爲空null,代表這個事件尚未被註冊過
if (subscriptions == null) {
//新建立一個arrayList 並把這個arraylist放入到 subscriptionsByEventType 這個HashMap當中
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);//爲了後期複用
}
//若是這個 subscriptions當中包含了新建立好的newSubscription的話就會拋出異常 ;
異常信息是 該訂閱者 已經註冊過了該事件 +該事件的類型
else {
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
//獲取到集合容納的大小
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
//根據優先級添加到arrayList當中的制定位置
subscriptions.add(i, newSubscription);
break;
}
}
//以訂閱者subscriber爲key,以eventType爲value,來獲取到eventType 的arrayList
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
//新建立一個並填入typesBySubscriber這個HashMap當中
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
//將這個事件類型放入到eventType的arrayList當中
subscribedEvents.add(eventType);
//判斷訂閱方法是否爲粘性事件,進一步判斷是否支持繼承關係
if (subscriberMethod.sticky) {
if (eventInheritance) {
//根據entrySet() 函數獲取全部粘性事件的Set集合
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
//依次遍歷 並經過eventType.isAssignableFrom()再次判斷是否有繼承關係
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
//若是有繼承關係的話,進行事件的分發操做
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
checkPostStickyEventToSubscription():
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
if (stickyEvent != null) {
postToSubscription(newSubscription, stickyEvent,
Looper.getMainLooper() == Looper.myLooper() );//經過該標誌位判斷是否在主線程當中
}
}
postToSubscription(): 核心方法使用的是 線程調度的 三個 post 方法
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
//若是處於POSTING 默認模式 就直接完成線程調用
invokeSubscriber(subscription, event);
break;
case MAIN:
//若是處於Ui主線程中,就直接調用invokeSubscriber
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
//若是不是在主線程,經過handlerPost中的enqueue方法 把須要的 ()入到隊列當中
mainThreadPoster.enqueue(subscription, event);
}
break;
case BACKGROUND:
if (isMainThread) {
//若是在Ui線程 ,就須要經過background 入隊列
backgroundPoster.enqueue(subscription, event);
} else {
//若是不在UI線程,區別於MAIN ,能夠直接調用
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
//無論在哪一個線程都會添加到隊列當中
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
invokeSubscriber(): //經過反射完成方法的調用
void invokeSubscriber(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception", e);
}
}
7、EventBus框架的Post事件發送 -核心的線程調度
EventBus.getDefault().post(new MyBusEvent("test fot eventbus"));
public void post(Object event) {
//經過ThreadLocal 獲取到一個發送狀態 postingThreadState
PostingThreadState postingState = currentPostingThreadState.get();
ps:PostingThreadState 發送事件的線程類的封裝類;
currentPostingThreadState 就是一個ThreadLocal ,線程獨有的,不會讓其餘線程共享當前線程的數據
//獲取到事件隊列,並將這個事件添加到隊列當中
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
//判斷是否在進行發送狀態,若是發送了就取消操做
if (!postingState.isPosting) {
//獲取到Looper判斷是否在主線程,獲取到當前線程的Looper 和主線程的Looper而後進行對比,若是對比結果isMainThread爲true 就繼續下面的操做
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
//將isPosting設爲true 表示這個事件正在分發了
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
//直到整個隊列都爲空,若是隊列不爲空則用postSingleEvent()發送事件
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
//將發生狀態清零
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
postSingleEvent():
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
//是否查看與這個事件有關的繼承關係
if (eventInheritance) {
//查找到全部繼承關係的事件類型
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
//若是沒有任何的事件,就會調用post(new NoSubscriberEvent() ),代表沒有訂閱者訂閱該事件
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
postSingleEventForEventType()://獲取subscriptionFound 標誌位
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
//在同步代碼塊中,經過sbuscriptionsByEventType的HashMap,獲取到一個訂閱event事件的集合
subscriptions = subscriptionsByEventType.get(eventClass);
}
…
//完成訂閱-核心的三個post調度方法
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
…
}