Android 經常使用開源框架源碼解析 系列 (八)Eventbus 事件發佈訂閱框架

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;
    …
}
相關文章
相關標籤/搜索