Android 注解反射實現(xiàn) EventButs

背景:

Android組件之間通訊的方式有很多,廣播 、intent 、handler、接口等這些都可以實現(xiàn)。網(wǎng)上開源框架EventBus是一款針對Android優(yōu)化的發(fā)布/訂閱事件總線。主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,線程之間傳遞消息.優(yōu)點是開銷小,代碼更優(yōu)雅。以及將發(fā)送者和接收者解耦。通過EventBus源碼自己實現(xiàn)線程之間消息傳遞。

1.介紹EventButs的使用方法:

一:注冊EventButs事件:
EventBus.getDefault().register(this);
二:監(jiān)聽EventButs事件:
 @Subscribe(threadMode = ThreadMode.MAIN)
    public void getEvent(EventBean bean){
        Log.e("====>", "thread = " + Thread.currentThread().getName());
        Log.e("======> ",bean.toString());
    }
三:發(fā)送EventButs事件:
   EventBus.getDefault().post(new EventBean("1111","22222"));

通過上面的代碼就可以實現(xiàn)事件消息在組件之間的傳遞,下面我將不改變開源框架的代碼格式,自己去實現(xiàn)EventButs:

第一步:定義注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME) // 注解會在class字節(jié)碼文件中存在,jvm在加載時可以通過反射的方式獲取該注解的內(nèi)容
public @interface Subscribe {

   ThreadMode threadMode() default ThreadMode.MAIN;
}

上面添加注解的枚舉類:定義的兩種類型一種指定主線程另一種為子線程

ublic enum ThreadMode {

    MAIN,
    BACKGROUND

}

第二步:注冊事件
 public void register(Object obj){
        // 先去數(shù)據(jù)源中獲取subcribleMethods,如果不存在,則去尋找方法并添加
        List<SubscribleMethod> list = cacheMap.get(obj);
        if(list == null){
            list = findSubscribleMethods(obj);
            cacheMap.put(obj,list);
        }
    }

上面的代碼主要為從緩存中獲取是否添加過監(jiān)聽,避免重復添加。

重點:

findSubscribleMethods 中主要將當前類以及父類中所有添加的注解一一遍歷出來,獲取注解類的回調(diào)方法、數(shù)據(jù)返回的線程模式、回調(diào)方法中的參數(shù)類 添加到map緩存 。具體代碼如下:

    public List<SubscribleMethod> findSubscribleMethods(Object obj){
        List<SubscribleMethod> list = new ArrayList<>();
        Class<?> clazz = obj.getClass();
        // 循環(huán)去查找父類是否存在subscrible注解方法
        while (clazz != null){

            // 判斷當前是否是系統(tǒng)類,如果是,就退出循環(huán)
            String name = clazz.getName();
            if(name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")){
                break;
            }

            // 得到所有的方法,這個clazz在本項目中,暫時指代的是MainActivity
            Method[] methods = clazz.getMethods();

            for(Method method : methods){
                // 通過注解找到我們需要注冊的方法
                Subscribe subscribe = method.getAnnotation(Subscribe.class);
                if(subscribe == null){
                    continue;
                }
                // 獲取方法中的參數(shù),并判斷
                Class<?>[] types = method.getParameterTypes();
                if(types.length != 1){
                    throw new RuntimeException("EventBus只能接受一個參數(shù)");
                }
                // 獲取線程模式
                ThreadMode threadMode = subscribe.threadMode();
                SubscribleMethod subscribleMethod = new SubscribleMethod(method,threadMode,types[0]);
                list.add(subscribleMethod);
            }
            clazz = clazz.getSuperclass();
        }
        return list;
    }
第三步:發(fā)送事件

發(fā)生事件為根據(jù)當前的發(fā)送的對象獲取緩存中的注解類,根據(jù)當前的線程調(diào)度通過反射去執(zhí)行注解類方法,實現(xiàn)數(shù)據(jù)的傳遞。

    public void post(final Object type){
        Set<Object> set = cacheMap.keySet();
        Iterator<Object> iterator = set.iterator();
        while (iterator.hasNext()){
            final Object obj = iterator.next();
            List<SubscribleMethod> list = cacheMap.get(obj);
            for(final SubscribleMethod subscribleMethod : list){
                // 簡單的理解:兩個列對比一下,看看是否一致 (不嚴謹?shù)恼f法)
                // a(subscribleMethod.getType())對象所對應的類信息,是b(type.getClass())對象所對應的類信息的父類或者父接口
                if(subscribleMethod.getType().isAssignableFrom(type.getClass())){
                    switch (subscribleMethod.getThreadMode()){
                        // 不管你在post是在主線程 還是在子線程,我都在主線程接受
                        case MAIN:
                            // 主 - 主
                            if(Looper.myLooper() == Looper.getMainLooper()){
                                invoke(subscribleMethod,obj,type);
                            }else{
                                // 子 - 主
                                mHandler.post(new Runnable() {
                                    @Override
                                    public void run() {
                                        invoke(subscribleMethod,obj,type);
                                    }
                                });
                            }
                            break;
                        case BACKGROUND:
                            // 主 - 子
                            if(Looper.myLooper() == Looper.getMainLooper()){
                                mExecutorService.execute(new Runnable() {
                                    @Override
                                    public void run() {
                                        invoke(subscribleMethod,obj,type);
                                    }
                                });
                            }else{
                                // 子 - 子
                                invoke(subscribleMethod,obj,type);
                            }
                            break;
                    }
                    
                }
            }
        }
    }

    private void invoke(SubscribleMethod subscribleMethod, Object obj, Object type) {
        Method method = subscribleMethod.getMethod();
        try {
            method.invoke(obj,type);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
image.png
 private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING:
                invokeSubscriber(subscription, event);
                break;
            case MAIN:
                if (isMainThread) {
                    invokeSubscriber(subscription, event);
                } else {
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case BACKGROUND:
                if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);
                } else {
                    invokeSubscriber(subscription, event);
                }
                break;
            case ASYNC:
                asyncPoster.enqueue(subscription, event);
                break;
            default:
                throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、簡歷準備 1、個人技能 (1)自定義控件、UI設(shè)計、常用動畫特效 自定義控件 ①為什么要自定義控件? Andr...
    lucas777閱讀 5,395評論 2 54
  • 面試題總結(jié) 通用 安卓學習途徑, 尋找資料學習的博客網(wǎng)站 AndroidStudio使用, 插件使用 安卓和蘋果的...
    JingBeibei閱讀 1,890評論 2 21
  • 類加載機制 如下圖所示,JVM類加載機制分為五個部分:加載,驗證,準備,解析,初始化,下面我們就分別來看一下這五個...
    舉頭望明月泣閱讀 1,258評論 0 0
  • Java基礎(chǔ) 什么是重載,什么是重寫?有什么區(qū)別?重載(Overload):(1)Overloading是一個類中...
    勤息嘻嘻嘻閱讀 702評論 0 1
  • 前面部分參考 原文鏈接:http://m.itdecent.cn/p/4bcd4c50fd6b 自己添加了一些...
    小沈新手閱讀 819評論 0 4

友情鏈接更多精彩內(nèi)容