在使用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 { }
第一個版本先不考慮事件調度模型,因此該註解目前只是做爲代碼標識,爲了內部處理而已。異步
註冊事件庫的時候能夠拿到該註冊類如Activty和對應改類中包涵了@BusReceiver註解的方法,並建立mMethodMap中(類型爲Map<Object,List<Method>>),便於後面查找。ide
此時根據事件類型,去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(); } } } } } }
基本的事件驅動思路就是這樣,轉換思路換來代碼的整潔,特別是App客戶端事件比較多的狀況比較適合用相似的庫,不過還有一些不足,後續繼續改進:
1 沒加入調度和分發模型,指定方法在特定的線程回調;
2 方法查找的效率問題,能夠放到map緩存,標準庫jdk,Android SDK中的方法是能夠跳過的;
3 註解處理的效率問題,判斷符合方法的條件的順序是否是能夠調整下;
4 能夠適當對方法Method對象作必定的抽象;
5 還沒加入支持事件繼承;性能