你知道event庫嗎?教你如何寫一個本身的event庫

在使用BmobSDK開發App的時候,會有不少異步回調,相似如登陸成功,插入數據成功的事件,雖然V3.5.0開始內部用rxjava去重構,也提供了rx風格的api,不過寫事件回調的方法仍是比較煩,這時候你能夠會用下流行的EventBus庫。下面就逐漸實現一個簡單的Demo,第一個版本,先不考慮優化和性能,線程切換之類的!java

沒有事件總線庫以前

你可能寫接口回調,發廣播,可是Activity和Fragment等組件交互也有點麻煩,寫起來代碼都是比較冗餘的!api

用了以後

代碼優雅,依賴於註解,使得代碼分離開來,在須要的時候send事件,對應註解到的特定方法就會被調用到,其實相似的還有Otto這個庫。緩存

開始實現

用法實例

// 註冊事件庫
Bus.getDefault().register(this);
// 建立自定義事件併發送事件
Event event = new Event();
event.setUserId("111");
Bus.getDefault().post(event);
// 指定了特定註解的合理方法會被調用
@BusReceiver
public void onEvent(Event event){
    System.out.println("getEvent " + event.getUserId());
}
// 註銷事件庫
Bus.getDefault().unRegister(this);

基本和EventBus的Api有點相似。併發

自定義註解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BusReceiver {
}

第一個版本先不考慮事件調度模型,因此該註解目前只是做爲代碼標識,爲了內部處理而已。異步

註解處理

基本思路

1 註冊事件庫

註冊事件庫的時候能夠拿到該註冊類如Activty和對應改類中包涵了@BusReceiver註解的方法,並建立mMethodMap中(類型爲Map<Object,List<Method>>),便於後面查找。ide

2 發送事件

此時根據事件類型,去mMethodMap中遍歷,事件類型判斷經過就調用method.invoke()調用特定的註解方法。基本都是對reflect下的api使用,好比拿到該類的方法,判斷註解並處理等的操做!post

代碼

public interface IBus {
    void register(Object target);
    void unRegister(Object target);
    void post(Object event);
}


public class Bus implements IBus {
    // 1 reg時 把target類型 記錄
    // 2 經過target類型(Class)找到含有指定@BusReceiver註解的方法 並拿到方法參數類型 以及事件類型
    // map<targetType,eventType>
    // post調用 Bus須要根據發送的事件類型找到 map中含有該事件類型的target中的方法集合並調用方法

    private static Bus INSTANCE = null;

    // 某target下的方法集合
    private Map<Object,List<Method>> mMethodMap = new HashMap<>();

    public static Bus getDefault(){
        if (INSTANCE == null){
            synchronized (Bus.class){
                if (INSTANCE == null){
                    INSTANCE = new Bus();
                }
            }
        }
        return INSTANCE;
    }

    @Override
    public void register(Object target) {
        // 找到target下的帶有@BusReceiver註解的合法方法並加到mMethodMap中
        List<Method> annotatedMethods = Utils.findAnnotatedMethods(target.getClass(), BusReceiver.class);
        mMethodMap.put(target,annotatedMethods);
    }

    @Override
    public void unRegister(Object target) {
        mMethodMap.remove(target);
    }

    @Override
    public void post(Object event) {
        Class<?> eventClass = event.getClass();
        // mMethodMap中的方法 須要判斷事件類型
        for (Map.Entry<Object, List<Method>> entry : mMethodMap.entrySet()) {
            Object target = entry.getKey();
            List<Method> methods = entry.getValue();
            if (methods == null || methods.isEmpty()){
                continue;
            }
            for (Method method : methods) {
                if (eventClass.equals(method.getParameterTypes()[0])){
                    try {
                        method.invoke(target,event);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

more

基本的事件驅動思路就是這樣,轉換思路換來代碼的整潔,特別是App客戶端事件比較多的狀況比較適合用相似的庫,不過還有一些不足,後續繼續改進:
1 沒加入調度和分發模型,指定方法在特定的線程回調;
2 方法查找的效率問題,能夠放到map緩存,標準庫jdk,Android SDK中的方法是能夠跳過的;
3 註解處理的效率問題,判斷符合方法的條件的順序是否是能夠調整下;
4 能夠適當對方法Method對象作必定的抽象;
5 還沒加入支持事件繼承;性能

相關文章
相關標籤/搜索