設計這個 BusUtils
實際上是在作 ApiUtils 時順手作的,由於二者實現方式基本一致,設計前我也沒想着要和 greenrobot 的 EventBus
一較高低,但設計完總須要一個對比,因此就拿業界最優秀的事件總線 EventBus
比較一下吧,而後就發現我這區區 300 行不到的 BusUtils
性能比 EventBus
要高出好多,固然,這一切的前提都是在 BusUtils
是切實可用而且有效的,它也是一款線程安全的事件總線,這些我都在單測中有作過實際測試的,不吹不擂,後面咱們拿數聽說話,有小夥伴不相信的話也能夠經過下載個人源碼來比較便可,單測地址:BusUtilsVsEventBusTest,Android 測試地址:BusCompareActivity,BusUtils
在 AucFrame 中的做用就是模塊內傳值,其扮演的角色以下所示:java
下面介紹其使用:android
在項目根目錄的 build.gradle
中添加 bus
插件:git
buildscript {
dependencies {
...
classpath 'com.blankj:bus-gradle-plugin:2.2'
}
}
複製代碼
而後在 application 模塊中使用該插件:github
apply plugin: "com.blankj.bus"
複製代碼
給你的項目添加 AndroidUtilCode 依賴:編程
api "com.blankj:utilcode:latest_version
複製代碼
若是你單純只想引入 BusUtils
也是能夠的,須要你本身拷貝一份這個類放到你工程裏,記得還要拷貝 ThreadUtils
哦,而後在 app 下的 build.gradle
中 配置 bus 的 DSL 域以下所示:json
bus {
busUtilsClass "com.xxx.xxx.BusUtils"
}
android {
...
}
複製代碼
能夠猜想到默認的 busUtilsClass 爲 com.blankj.utilcode.util.BusUtils
哈。api
若是開啓混淆的話還須要配置你的 BusUtils
中註解方法的防混淆,若是直接用 AndroidUtilCode 的話是不須要你配置的,我已經幫你作完了,配置你本身的 BusUtils
防混淆應該以下所示:安全
-keepattributes *Annotation*
-keepclassmembers class * {
@com.xxx.xxx.BusUtils$Bus <methods>;
}
複製代碼
固然,若是你項目是開啓混淆的話,全量引入 AndroidUtilCode 也是能夠的,混淆會幫你去除未使用到的類和方法。bash
好了,插件和依賴都配置完畢,下面介紹基本使用。微信
public static final String TAG_NO_PARAM = "TagNoParam";
public static final String TAG_ONE_PARAM = "TagOneParam";
@BusUtils.Bus(tag = TAG_NO_PARAM)
public void noParamFun() {/* Do something */}
@BusUtils.Bus(tag = TAG_ONE_PARAM)
public void oneParamFun(String param) {/* Do something */}
@Override
public void onStart() {
super.onStart();
BusUtils.register(this);
}
@Override
public void onStop() {
super.onStop();
BusUtils.unregister(this);
}
BusUtils.post(TAG_NO_PARAM);// noParamFun() will receive
BusUtils.post(TAG_ONE_PARAM, "param");// oneParamFun() will receive
複製代碼
使用過 EventBus
的確定一會兒就能看懂。
支持粘性事件,也就是先發送,而後在訂閱的時候接收到以前發送的粘性事件,把其消費掉,使用方式和 EventBus
一致,就是在 @BusUtils.Bus
註解中設置 sticky = true
,具體例子以下所示:
public static final String TAG_NO_PARAM_STICKY = "TagNoParamSticky";
@BusUtils.Bus(tag = TAG_NO_PARAM_STICKY, sticky = true)
public void noParamStickyFun() {/* Do something */}
BusUtils.postSticky(TAG_NO_PARAM_STICKY);
BusUtils.register(xxx);// will invoke noParamStickyFun
BusUtils.removeSticky(TAG_NO_PARAM_STICKY);// When u needn't use the sticky, remove it
BusUtils.unregister(xxx);
複製代碼
線程切換使用的是 ThreadUtils 中的線程池,它具備安全的 Cached 線程池,以及 MAIN, IO, CPU, CACHED, SINGLE 線程池,默認不設置的話就是在提交的線程 POSTING,使用的話就是在 @BusUtils.Bus
註解中設置 threadMode = BusUtils.ThreadMode.xx
便可。
要想工具用得舒服,規範確定要遵照的,所謂無規矩不成方圓,否則五花八門的問題確定一堆堆,這裏推薦以下規範:
public
的。BusUtils
是用於模塊內調用,因此能夠寫一個 BusConfig
的類來保存一個模塊內全部 bus 的 Tag
,方便查找到使用方及調用方。Tag
中最好還能帶有業務模塊後綴名防止重複,是 sticky 類型的話也帶上 sticky,指定具體線程的話也帶上線程名,例如:update_avatar_sticky_main_info
這個 Tag
,讓人直接望文生義。BusUtils
中事件傳輸的的 bean
都須要 keep
下來,不然開啓混淆後會找不到該實體對象而報錯。使用已經介紹完畢,下面咱們來和 EventBus
對比下性能。
首先,把二者的事件定義好,由於比較的是事件達到的快慢,因此內部都是空實現便可,具體代碼以下所示:
@Subscribe
public void eventBusFun(String param) {
}
@BusUtils.Bus(tag = "busUtilsFun")
public void busUtilsFun(String param) {
}
複製代碼
BusUtils
在編譯時會根據 @BusUtils.Bus
註解生成一份記錄 tag 和 方法簽名的映射表,由於是在編譯時完成的,這裏咱們經過反射來完成。
@Before
public void setUp() throws Exception {
// 這一步是在 AOP 的時候注入的,這裏經過反射來注入 busUtilsFun 事件,效果是同樣的。
ReflectUtils getInstance = ReflectUtils.reflect(BusUtils.class).method("getInstance");
getInstance.method("registerBus", "busUtilsFun", BusUtilsVsEventBusTest.class.getName(), "busUtilsFun", String.class.getName(), "param", false, "POSTING");
}
複製代碼
經過比較以下幾點的測試來完成對比:
測試機器以下所示:
macOS: 2.2GHz Intel Core i7 16GB
一加6: Android 9 8GB
複製代碼
在 Android 上,咱們加入 EventBus
的註解處理器來提高 EventBus
效率,讓其在最優狀況下和 BusUtils
比較。
接下來,咱們把測試的模板代碼寫好,方便後續能夠直接把二者比較的代碼往回調中塞入便可,具體代碼以下所示:
/** * @param name 傳入的測試函數名 * @param sampleSize 樣本的數量 * @param times 每次執行的次數 * @param callback 比較的回調函數 */
private void compareWithEventBus(String name, int sampleSize, int times, CompareCallback callback) {
long[][] dur = new long[2][sampleSize];
for (int i = 0; i < sampleSize; i++) {
long cur = System.currentTimeMillis();
for (int j = 0; j < times; j++) {
callback.runEventBus();
}
dur[0][i] = System.currentTimeMillis() - cur;
cur = System.currentTimeMillis();
for (int j = 0; j < times; j++) {
callback.runBusUtils();
}
dur[1][i] = System.currentTimeMillis() - cur;
callback.restState();
}
long eventBusAverageTime = 0;
long busUtilsAverageTime = 0;
for (int i = 0; i < sampleSize; i++) {
eventBusAverageTime += dur[0][i];
busUtilsAverageTime += dur[1][i];
}
System.out.println(
name +
"\nEventBusCostTime: " + eventBusAverageTime / sampleSize +
"\nBusUtilsCostTime: " + busUtilsAverageTime / sampleSize
);
}
public interface CompareCallback {
void runEventBus();
void runBusUtils();
void restState();
}
複製代碼
下面就讓咱們來一一對比測試。
/** * 註冊 10000 個訂閱者,共執行 10 次取平均值 */
@Test
public void compareRegister10000Times() {
final List<BusUtilsVsEventBusTest> eventBusTests = new ArrayList<>();
final List<BusUtilsVsEventBusTest> busUtilsTests = new ArrayList<>();
compareWithEventBus("Register 10000 times.", 10, 10000, new CompareCallback() {
@Override
public void runEventBus() {
BusUtilsVsEventBusTest test = new BusUtilsVsEventBusTest();
EventBus.getDefault().register(test);
eventBusTests.add(test);
}
@Override
public void runBusUtils() {
BusUtilsVsEventBusTest test = new BusUtilsVsEventBusTest();
BusUtils.register(test);
busUtilsTests.add(test);
}
@Override
public void restState() {
for (BusUtilsVsEventBusTest test : eventBusTests) {
EventBus.getDefault().unregister(test);
}
eventBusTests.clear();
for (BusUtilsVsEventBusTest test : busUtilsTests) {
BusUtils.unregister(test);
}
busUtilsTests.clear();
}
});
}
// MacOS Output:
// Register 10000 times.
// EventBusCostTime: 427
// BusUtilsCostTime: 41
// 一加6 Output:
// Register 10000 times.
// EventBusCostTime: 1268
// BusUtilsCostTime: 399
複製代碼
/** * 向 1 個訂閱者發送 * 1000000 次,共執行 10 次取平均值 */
@Test
public void comparePostTo1Subscriber1000000Times() {
comparePostTemplate("Post to 1 subscriber 1000000 times.", 1, 1000000);
}
// MacOS Output:
// Post to 1 subscriber 1000000 times.
// EventBusCostTime: 145
// BusUtilsCostTime: 33
// 一加6 Output:
// Post to 1 subscriber 1000000 times.
// EventBusCostTime: 1247
// BusUtilsCostTime: 696
private void comparePostTemplate(String name, int subscribeNum, int postTimes) {
final List<BusUtilsVsEventBusTest> tests = new ArrayList<>();
for (int i = 0; i < subscribeNum; i++) {
BusUtilsVsEventBusTest test = new BusUtilsVsEventBusTest();
EventBus.getDefault().register(test);
BusUtils.register(test);
tests.add(test);
}
compareWithEventBus(name, 10, postTimes, new CompareCallback() {
@Override
public void runEventBus() {
EventBus.getDefault().post("EventBus");
}
@Override
public void runBusUtils() {
BusUtils.post("busUtilsFun", "BusUtils");
}
@Override
public void restState() {
}
});
for (BusUtilsVsEventBusTest test : tests) {
EventBus.getDefault().unregister(test);
BusUtils.unregister(test);
}
}
複製代碼
/** * 向 100 個訂閱者發送 * 100000 次,共執行 10 次取平均值 */
@Test
public void comparePostTo100Subscribers10000Times() {
comparePostTemplate("Post to 100 subscribers 100000 times.", 100, 100000);
}
// MacOS Output:
// Post to 100 subscribers 100000 times.
// EventBusCostTime: 139
// BusUtilsCostTime: 79
// 一加6 Output:
// Post to 100 subscribers 100000 times.
// EventBusCostTime: 3092
// BusUtilsCostTime: 2900
複製代碼
/** * 註銷 10000 個訂閱者,共執行 10 次取平均值 */
@Test
public void compareUnregister10000Times() {
final List<BusUtilsVsEventBusTest> tests = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
BusUtilsVsEventBusTest test = new BusUtilsVsEventBusTest();
EventBus.getDefault().register(test);
BusUtils.register(test);
tests.add(test);
}
compareWithEventBus("Unregister 10000 times.", 10, 1, new CompareCallback() {
@Override
public void runEventBus() {
for (BusUtilsVsEventBusTest test : tests) {
EventBus.getDefault().unregister(test);
}
}
@Override
public void runBusUtils() {
for (BusUtilsVsEventBusTest test : tests) {
BusUtils.unregister(test);
}
}
@Override
public void restState() {
for (BusUtilsVsEventBusTest test : tests) {
EventBus.getDefault().register(test);
BusUtils.register(test);
}
}
});
for (BusUtilsVsEventBusTest test : tests) {
EventBus.getDefault().unregister(test);
BusUtils.unregister(test);
}
}
// MacOS Output:
// Unregister 10000 times.
// EventBusCostTime: 231
// BusUtilsCostTime: 23
// 一加6 Output:
// Unregister 10000 times.
// EventBusCostTime: 800
// BusUtilsCostTime: 199
複製代碼
爲了方便觀察,咱們生成一份圖表來比較二者之間的性能:
圖表中分別對四個函數在 MacOS 和 OnePlus6 中的表現進行統計,每一個函數中從左向右分別是 「MacOS 的 BusUtils」、「MacOS 的 EventBus」、「OnePlus6 的 BusUtils」、「OnePlus6 的 EventBus」,能夠發現,BusUtils 在註冊和註銷上基本比 EventBus
要快上好幾倍,BusUtils 在向少許訂閱者發送屢次事件比 EventBus
也快上好多,在向多個訂閱者發送屢次事件也比 EventBus
快上些許。
基於以上說的這麼多,若是你項目中事件總線用得比較頻繁,那麼能夠試着用個人 BusUtils
來替代 EventBus
來提高性能,或者在新的項目中,你也能夠直接使用性能更好的 BusUtils
。
下面來總結下 BusUtils
的優勢:
BusUtils
是經過事件 Tag
來肯定惟一事件的,因此接收函數支持無參或者一個參數,而 EventBus
只能經過 MessageEvent 來肯定具體的接收者,只能接收一個參數,即使僅僅是通知,也須要定義一個 MessageEvent,因此,BusUtils
傳參更靈活。BusUtils
在應用到項目中後,編譯後便會在 application 中生成 __bus__.json
事件列表,如上生成的事件列表以下所示:{
"BusUtilsClass": "com.blankj.utilcode.util.BusUtils",
"rightBus": {
"noParamFun": "{ desc: com.blankj.utilcode.pkg.feature.bus.BusActivity#noParamFun(), threadMode: POSTING }",
"oneParamFun": "{ desc: com.blankj.utilcode.pkg.feature.bus.BusActivity#oneParamFun(java.lang.String param), threadMode: POSTING }"
},
"wrongBus": {}
}
複製代碼
修改 oneParamFun
爲兩個參數的話,爲了確保項目不會由於 BusUtils
在運行時崩潰,api
插件會使其在編譯時就不過,此時 __bus__.json
文件以下所示,提示你參數個數不對:
{
"BusUtilsClass": "com.blankj.utilcode.util.BusUtils",
"rightBus": {
"noParamFun": "{ desc: com.blankj.utilcode.pkg.feature.bus.BusActivity#noParamFun(), threadMode: POSTING }",
},
"wrongBus": {
"oneParamFun": "{ desc: com.blankj.utilcode.pkg.feature.bus.BusActivity#oneParamFun(java.lang.String param, java.lang.String param1), threadMode: POSTING, paramSize: 2 }"
}
複製代碼
同理,若是兩個 bus 的 (2.1 版本已支持 Tag 一對多及事件優先級)Tag
相同了,也會編譯不過,提示你項目中存在 Tag
相同的 bus。
因此,BusUtils
比 EventBus
更友好。
BusUtils
比 EventBus
代碼少得太多,BusUtils
的源碼只有區區 300 行,而 EventBus
3000 行確定是不止的哈。BusUtils
比 EventBus
性能更好。bus 插件的源碼在這裏:bus 插件源碼傳送門,該插件經過 Gradle 的 transform 來完成對 BusUtils.init()
作注入,下面來一步步分析:
不明白 transform 的能夠先去了解下,簡單來講 transform 就是專門用來作字節碼插入操做的,最多見的就是 AOP(面向切面編程),這部分我就不科普了,有興趣的能夠本身搜索瞭解。
說到字節碼操做,那就又有知識點了,想要上手快速簡單的可使用 javassist
,不過,我選擇了更強大快速的 ASM
,這裏我就不詳細介紹了,有興趣的能夠本身去學習,ASM
其實也很簡單的,在 ASM Bytecode Outline 這個插件幫助下寫得仍是很快的。
經過 ASM 掃描出全部帶有 @BusUtils.Bus
註解的函數,讀取並保存註解的值和函數的參數信息,相關代碼以下所示:
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
className = name.replace("/", ".");
super.visit(version, access, name, signature, superName, interfaces);
}
@Override
public MethodVisitor visitMethod(int access, String funName, String desc, String signature, String[] exceptions) {
if (cv == null) return null;
MethodVisitor mv = cv.visitMethod(access, funName, desc, signature, exceptions);
busInfo = null;
mv = new AdviceAdapter(Opcodes.ASM5, mv, access, funName, desc) {
@Override
public AnnotationVisitor visitAnnotation(String desc1, boolean visible) {
final AnnotationVisitor av = super.visitAnnotation(desc1, visible);
if (("L" + mBusUtilsClass + "$Bus;").equals(desc1)) {
busInfo = new BusInfo(className, funName);
funParamDesc = desc.substring(1, desc.indexOf(")"));
return new AnnotationVisitor(Opcodes.ASM5, av) {
@Override
public void visit(String name, Object value) {// 可獲取註解的值
super.visit(name, value);
if ("tag".equals(name)) {
tag = (String) value;
} else if ("sticky".equals(name) && (Boolean) value) {
busInfo.sticky = true;
}
}
@Override
public void visitEnum(String name, String desc, String value) {
super.visitEnum(name, desc, value);
if ("threadMode".equals(name)) {
busInfo.threadMode = value;
}
}
};
}
return av;
}
@Override
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
super.visitLocalVariable(name, desc, signature, start, end, index);// 獲取方法參數信息
if (busInfo != null && !funParamDesc.equals("")) {
if ("this".equals(name)) {
return;
}
funParamDesc = funParamDesc.substring(desc.length());// 每次去除參數直到爲 "",那麼以後的就不是參數了
busInfo.paramsInfo.add(new BusInfo.ParamsInfo(Type.getType(desc).getClassName(), name));
if (busInfo.isParamSizeNoMoreThanOne && busInfo.paramsInfo.size() > 1) {
busInfo.isParamSizeNoMoreThanOne = false;
}
}
}
@Override
public void visitEnd() {
super.visitEnd();
if (busInfo != null) {
List<BusInfo> infoList = mBusMap.get(tag);
if (infoList == null) {
infoList = new ArrayList<>();
mBusMap.put(tag, infoList);
} else if (infoList.size() == 0) {
mBusMap.put(tag, infoList);
} else if (infoList.size() == 1) {
BusInfo info0 = infoList.get(0);
info0.isTagRepeat = true;
busInfo.isTagRepeat = true;
} else {
busInfo.isTagRepeat = true;
}
infoList.add(busInfo);
}
}
};
return mv;
}
複製代碼
而後往 BusUtils.init()
插入掃描出來的內容,好比上面提到的 oneParamFun
這個函數,那麼其最終插入的代碼以下所示:
private void init() {
this.registerBus("TagOneParam", "com.blankj.bus.BusTest", "oneParamFun", "java.lang.String", "param", false, "POSTING");
}
複製代碼
其 ASM 插入的代碼以下所示:
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
if (!"init".equals(name)) {
return super.visitMethod(access, name, descriptor, signature, exceptions);
}
// 往 init() 函數中寫入
if (cv == null) return null;
MethodVisitor mv = cv.visitMethod(access, name, descriptor, signature, exceptions);
mv = new AdviceAdapter(Opcodes.ASM5, mv, access, name, descriptor) {
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
return super.visitAnnotation(desc, visible);
}
@Override
protected void onMethodEnter() {
super.onMethodEnter();
}
@Override
protected void onMethodExit(int opcode) {
super.onMethodExit(opcode);
for (Map.Entry<String, List<BusInfo>> busEntry : mBusMap.entrySet()) {
List<BusInfo> infoList = busEntry.getValue();
if (infoList.size() != 1) continue;
BusInfo busInfo = infoList.get(0);
if (!busInfo.isParamSizeNoMoreThanOne) continue;
mv.visitVarInsn(ALOAD, 0);
mv.visitLdcInsn(busEntry.getKey());
mv.visitLdcInsn(busInfo.className);
mv.visitLdcInsn(busInfo.funName);
if (busInfo.paramsInfo.size() == 1) {
mv.visitLdcInsn(busInfo.paramsInfo.get(0).className);
mv.visitLdcInsn(busInfo.paramsInfo.get(0).name);
} else {
mv.visitLdcInsn("");
mv.visitLdcInsn("");
}
mv.visitInsn(busInfo.sticky ? ICONST_1 : ICONST_0);
mv.visitLdcInsn(busInfo.threadMode);
mv.visitMethodInsn(INVOKESPECIAL, mBusUtilsClass, "registerBus", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;)V", false);
}
}
};
return mv;
}
複製代碼
接下來看下 BusUtils.registerBus
的實現:
private void registerBus(String tag, String className, String funName, String paramType, String paramName, boolean sticky, String threadMode) {
mTag_BusInfoMap.put(tag, new BusInfo(className, funName, paramType, paramName, sticky, threadMode));
}
複製代碼
很簡單,就是往 mTag_BusInfoMap
中插入了 key 爲 tag
,value 爲 BusInfo
的一個實例,這樣便把一個事件保留了下來。
接下來就是使用了,一開始咱們都是先 register,源碼以下所示:
public static void register(final Object bus) {
getInstance().registerInner(bus);
}
private void registerInner(final Object bus) {
if (bus == null) return;
String className = bus.getClass().getName();
synchronized (mClassName_BusesMap) {
Set<Object> buses = mClassName_BusesMap.get(className);
if (buses == null) {
buses = new CopyOnWriteArraySet<>();
mClassName_BusesMap.put(className, buses);
}
buses.add(bus);
}
processSticky(bus);
}
複製代碼
咱們獲取 bus 的類名,而後對 mClassName_BusesMap
加鎖來把它插入到 mClassName_BusesMap
的 value 的集合中,能夠看到咱們用了線程安全的 CopyOnWriteArraySet
集合,而後還須要處理下以前是否訂閱過粘性事件 processSticky
,到這裏 register 便結束了。
而後就是 post
來發送事件了,源碼以下:
public static void post(final String tag) {
post(tag, NULL);
}
public static void post(final String tag, final Object arg) {
getInstance().postInner(tag, arg);
}
private void postInner(final String tag, final Object arg) {
postInner(tag, arg, false);
}
private void postInner(final String tag, final Object arg, final boolean sticky) {
BusInfo busInfo = mTag_BusInfoMap.get(tag);
if (busInfo == null) {
Log.e(TAG, "The bus of tag <" + tag + "> is not exists.");
return;
}
if (busInfo.method == null) {
Method method = getMethodByBusInfo(busInfo);
if (method == null) {
return;
}
busInfo.method = method;
}
invokeMethod(tag, arg, busInfo, sticky);
}
private Method getMethodByBusInfo(BusInfo busInfo) {
try {
if ("".equals(busInfo.paramType)) {
return Class.forName(busInfo.className).getDeclaredMethod(busInfo.funName);
} else {
return Class.forName(busInfo.className).getDeclaredMethod(busInfo.funName, Class.forName(busInfo.paramType));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
private void invokeMethod(final String tag, final Object arg, final BusInfo busInfo, final boolean sticky) {
Runnable runnable = new Runnable() {
@Override
public void run() {
realInvokeMethod(tag, arg, busInfo, sticky);
}
};
switch (busInfo.threadMode) {
case "MAIN":
Utils.runOnUiThread(runnable);
return;
case "IO":
ThreadUtils.getIoPool().execute(runnable);
return;
case "CPU":
ThreadUtils.getCpuPool().execute(runnable);
return;
case "CACHED":
ThreadUtils.getCachedPool().execute(runnable);
return;
case "SINGLE":
ThreadUtils.getSinglePool().execute(runnable);
return;
default:
runnable.run();
}
}
private void realInvokeMethod(final String tag, Object arg, BusInfo busInfo, boolean sticky) {
Set<Object> buses = mClassName_BusesMap.get(busInfo.className);
if (buses == null || buses.size() == 0) {
if (!sticky) {
Log.e(TAG, "The bus of tag <" + tag + "> was not registered before.");
return;
} else {
return;
}
}
try {
if (arg == NULL) {
for (Object bus : buses) {
busInfo.method.invoke(bus);
}
} else {
for (Object bus : buses) {
busInfo.method.invoke(bus, arg);
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
複製代碼
能夠看到代碼仍是比較多的,不過別急,咱們一步步來仍是很簡單的,首先在咱們以前注入的 mTag_BusInfoMap
中查找是否有該 tag
的 BusInfo
,沒有的話就輸出錯誤日誌直接返回。
而後咱們根據獲取到的 BusInfo
來找到 method
實例,BusInfo
第一次會把 method
保存在實例中,以後調用的話直接從實例中取出 method
便可。
接着咱們從 BusInfo
中取出線程信息,最後在線程中執行 method
的反射,大致就是這樣,具體細節的話仍是須要本身分析源碼。
最後就是 unregister
了:
public static void unregister(final Object bus) {
getInstance().unregisterInner(bus);
}
private void unregisterInner(final Object bus) {
if (bus == null) return;
String className = bus.getClass().getName();
synchronized (mClassName_BusesMap) {
Set<Object> buses = mClassName_BusesMap.get(className);
if (buses == null || !buses.contains(bus)) {
Log.e(TAG, "The bus of <" + bus + "> was not registered before.");
return;
}
buses.remove(bus);
}
}
複製代碼
unregister
和 register
相反,就是從 mClassName_BusesMap
的 value 集合中移除,一樣須要對 mClassName_BusesMap
加鎖哦。
歡迎加入個人知識星球「基你太美」,我會在星球中分享 AucFrame 框架、大廠面經、AndroidUtilCode 更詳盡的說明...一切我所瞭解的知識,你能夠經過支付進入個人星球「基你太美」進行體驗,加入後優先觀看星球中精華的部分,若是以爲星球的內容對自身沒有收益,你能夠自行申請退款退出星球,也不必加我好友;若是你已肯定要留在個人星球,能夠經過掃描以下二維碼(備註:基你太美+你的星球暱稱)加我我的微信,方便我後續拉你進羣(PS:進得越早價格越便宜)。