美文网首页
otto源码解析

otto源码解析

作者: heiheiwanne | 来源:发表于2017-03-10 18:46 被阅读69次

    tips:

    • 接口的使用
    public interface ThreadEnforcer {
        ThreadEnforcer ANY = new ThreadEnforcer() {
            public void enforce(Bus bus) {
            }
        };
        ThreadEnforcer MAIN = new ThreadEnforcer() {
            public void enforce(Bus bus) {
                if(Looper.myLooper() != Looper.getMainLooper()) {
                    throw new IllegalStateException("Event bus " + bus + " accessed from non-main thread " + Looper.myLooper());
                }
            }
        };
    
        void enforce(Bus var1);
    }
    
    • 判断是否为主线程:
    if(Looper.myLooper() != Looper.getMainLooper()) {
                    throw new IllegalStateException("Event bus " + bus + " accessed from non-main thread " + Looper.myLooper());
                }
    
    • 主要是Bus.java里面的代码:
      关键的方法有

    public void register(Object object)
    该方法的作用是查找object里面所有带有Produce和Subscribe注解的方法,并保存在Map中,并且会立即执行Produce注解的方法。

    private static void loadAnnotatedMethods(Class<?> listenerClass) {
            HashMap subscriberMethods = new HashMap();
            HashMap producerMethods = new HashMap();
            Method[] arr$ = listenerClass.getDeclaredMethods();//将所有的方法都取出来
            int len$ = arr$.length;
    
            for(int i$ = 0; i$ < len$; ++i$) {
                Method method = arr$[i$];
                Class[] parameterTypes;
                Class eventType;
                if(method.isAnnotationPresent(Subscribe.class)) {  //自定义注解获取方法
                    parameterTypes = method.getParameterTypes();
                    if(parameterTypes.length != 1) {
                        throw new IllegalArgumentException("Method " + method + " has @Subscribe annotation but requires " + parameterTypes.length + " arguments.  Methods must require a single argument.");
                    }
    
                    eventType = parameterTypes[0];
                    if(eventType.isInterface()) {
                        throw new IllegalArgumentException("Method " + method + " has @Subscribe annotation on " + eventType + " which is an interface.  Subscription must be on a concrete class type.");
                    }
    
                    if((method.getModifiers() & 1) == 0) {
                        throw new IllegalArgumentException("Method " + method + " has @Subscribe annotation on " + eventType + " but is not \'public\'.");
                    }
    
                    Object methods = (Set)subscriberMethods.get(eventType);
                    if(methods == null) {
                        methods = new HashSet();
                        subscriberMethods.put(eventType, methods);
                    }
    
                    ((Set)methods).add(method);
                } else if(method.isAnnotationPresent(Produce.class)) {
                    parameterTypes = method.getParameterTypes();
                    if(parameterTypes.length != 0) {
                        throw new IllegalArgumentException("Method " + method + "has @Produce annotation but requires " + parameterTypes.length + " arguments.  Methods must require zero arguments.");
                    }
    
                    if(method.getReturnType() == Void.class) {
                        throw new IllegalArgumentException("Method " + method + " has a return type of void.  Must declare a non-void type.");
                    }
    
                    eventType = method.getReturnType();
                    if(eventType.isInterface()) {
                        throw new IllegalArgumentException("Method " + method + " has @Produce annotation on " + eventType + " which is an interface.  Producers must return a concrete class type.");
                    }
    
                    if((method.getModifiers() & 1) == 0) {
                        throw new IllegalArgumentException("Method " + method + " has @Produce annotation on " + eventType + " but is not \'public\'.");
                    }
    
                    if(producerMethods.containsKey(eventType)) {
                        throw new IllegalArgumentException("Producer for type " + eventType + " has already been registered.");
                    }
    
                    producerMethods.put(eventType, method);
                }
            }
    
            PRODUCERS_CACHE.put(listenerClass, producerMethods); //将所有带有Subscribe.class gen跟Produce.class 注解的方法保存下来
            SUBSCRIBERS_CACHE.put(listenerClass, subscriberMethods);
        }
    
    • public void post(Object event)
      发送事件event,根据之前注册过的object里面的方法,查找参数为event的Subscribe方法,并invoke该方法。这样就达到了post之后,调用对应Subscribe方法的目的。
     EventHandler(Object target, Method method) {
            if(target == null) {
                throw new NullPointerException("EventHandler target cannot be null.");
            } else if(method == null) {
                throw new NullPointerException("EventHandler method cannot be null.");
            } else {
                this.target = target;
                this.method = method;
                method.setAccessible(true);  //注意此处的开关是关闭java的安全检查机制,能提高反射的性能
                boolean prime = true;
                this.hashCode = (31 + method.hashCode()) * 31 + target.hashCode();
            }
        }
        
     public void handleEvent(Object event) throws InvocationTargetException {
            try {
                this.method.invoke(this.target, new Object[]{event});
            } catch (IllegalAccessException var3) {
                throw new AssertionError(var3);
            } catch (InvocationTargetException var4) {
                if(var4.getCause() instanceof Error) {
                    throw (Error)var4.getCause();
                } else {
                    throw var4;
                }
            }
        }
    
    • public void unregister(Object object)
      注销object,删除掉map中保存的object的方法,释放object,防止内存泄露。

    总结:otto将所有带有注解的类存到map里面,包含了类,方法名,参数,等post或者有注解的时候,使用invoke 反射调用,所以都是使用了反射实现。

    这里有一个小工具类,以后可以直接copy ,查找annotion

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package com.squareup.otto;
    
    import com.squareup.otto.EventHandler;
    import com.squareup.otto.EventProducer;
    import com.squareup.otto.Produce;
    import com.squareup.otto.Subscribe;
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Set;
    import java.util.Map.Entry;
    
    final class AnnotatedHandlerFinder {
        private static final Map<Class<?>, Map<Class<?>, Method>> PRODUCERS_CACHE = new HashMap();
        private static final Map<Class<?>, Map<Class<?>, Set<Method>>> SUBSCRIBERS_CACHE = new HashMap();
    
        private static void loadAnnotatedMethods(Class<?> listenerClass) {
            HashMap subscriberMethods = new HashMap();
            HashMap producerMethods = new HashMap();
            Method[] arr$ = listenerClass.getDeclaredMethods();
            int len$ = arr$.length;
    
            for(int i$ = 0; i$ < len$; ++i$) {
                Method method = arr$[i$];
                Class[] parameterTypes;
                Class eventType;
                if(method.isAnnotationPresent(Subscribe.class)) {
                    parameterTypes = method.getParameterTypes();
                    if(parameterTypes.length != 1) {
                        throw new IllegalArgumentException("Method " + method + " has @Subscribe annotation but requires " + parameterTypes.length + " arguments.  Methods must require a single argument.");
                    }
    
                    eventType = parameterTypes[0];
                    if(eventType.isInterface()) {
                        throw new IllegalArgumentException("Method " + method + " has @Subscribe annotation on " + eventType + " which is an interface.  Subscription must be on a concrete class type.");
                    }
    
                    if((method.getModifiers() & 1) == 0) {
                        throw new IllegalArgumentException("Method " + method + " has @Subscribe annotation on " + eventType + " but is not \'public\'.");
                    }
    
                    Object methods = (Set)subscriberMethods.get(eventType);
                    if(methods == null) {
                        methods = new HashSet();
                        subscriberMethods.put(eventType, methods);
                    }
    
                    ((Set)methods).add(method);
                } else if(method.isAnnotationPresent(Produce.class)) {
                    parameterTypes = method.getParameterTypes();
                    if(parameterTypes.length != 0) {
                        throw new IllegalArgumentException("Method " + method + "has @Produce annotation but requires " + parameterTypes.length + " arguments.  Methods must require zero arguments.");
                    }
    
                    if(method.getReturnType() == Void.class) {
                        throw new IllegalArgumentException("Method " + method + " has a return type of void.  Must declare a non-void type.");
                    }
    
                    eventType = method.getReturnType();
                    if(eventType.isInterface()) {
                        throw new IllegalArgumentException("Method " + method + " has @Produce annotation on " + eventType + " which is an interface.  Producers must return a concrete class type.");
                    }
    
                    if((method.getModifiers() & 1) == 0) {
                        throw new IllegalArgumentException("Method " + method + " has @Produce annotation on " + eventType + " but is not \'public\'.");
                    }
    
                    if(producerMethods.containsKey(eventType)) {
                        throw new IllegalArgumentException("Producer for type " + eventType + " has already been registered.");
                    }
    
                    producerMethods.put(eventType, method);
                }
            }
    
            PRODUCERS_CACHE.put(listenerClass, producerMethods);
            SUBSCRIBERS_CACHE.put(listenerClass, subscriberMethods);
        }
    
        static Map<Class<?>, EventProducer> findAllProducers(Object listener) {
            Class listenerClass = listener.getClass();
            HashMap handlersInMethod = new HashMap();
            if(!PRODUCERS_CACHE.containsKey(listenerClass)) {
                loadAnnotatedMethods(listenerClass);
            }
    
            Map methods = (Map)PRODUCERS_CACHE.get(listenerClass);
            if(!methods.isEmpty()) {
                Iterator i$ = methods.entrySet().iterator();
    
                while(i$.hasNext()) {
                    Entry e = (Entry)i$.next();
                    EventProducer producer = new EventProducer(listener, (Method)e.getValue());
                    handlersInMethod.put(e.getKey(), producer);
                }
            }
    
            return handlersInMethod;
        }
    
        static Map<Class<?>, Set<EventHandler>> findAllSubscribers(Object listener) {
            Class listenerClass = listener.getClass();
            HashMap handlersInMethod = new HashMap();
            if(!SUBSCRIBERS_CACHE.containsKey(listenerClass)) {
                loadAnnotatedMethods(listenerClass);
            }
    
            Map methods = (Map)SUBSCRIBERS_CACHE.get(listenerClass);
            if(!methods.isEmpty()) {
                Iterator i$ = methods.entrySet().iterator();
    
                while(i$.hasNext()) {
                    Entry e = (Entry)i$.next();
                    HashSet handlers = new HashSet();
                    Iterator i$1 = ((Set)e.getValue()).iterator();
    
                    while(i$1.hasNext()) {
                        Method m = (Method)i$1.next();
                        handlers.add(new EventHandler(listener, m));
                    }
    
                    handlersInMethod.put(e.getKey(), handlers);
                }
            }
    
            return handlersInMethod;
        }
    
        private AnnotatedHandlerFinder() {
        }
    }
    
    

    相关文章

      网友评论

          本文标题:otto源码解析

          本文链接:https://www.haomeiwen.com/subject/lojogttx.html