美文网首页Android开发Android开发经验谈Android开发
android 源码设计模式读书笔记(七)观察者模式+注解

android 源码设计模式读书笔记(七)观察者模式+注解

作者: 刘景昌 | 来源:发表于2019-07-25 15:47 被阅读9次

    定义:定义对象之间的一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于他的UI依赖于他的对象都会得到通知并自动更新。
    使用场景:
    (1)关联行为场景,需要注意的是,关联行为是可拆分的,而不是组合关系
    (2)事件多级触发场景
    (3)事件总线处理机制
    基础UML


    image.png

    关于注解
    定义:注解用于为Java提供元数据,作为元数据,注解不影响代码执行,但某些类型注解也可以用于这一目的,注解从Java5开始引入
    注解语法

    @Retention(RetentionPolicy.CLASS)
    @Target({ElementType.FIELD, ElementType.TYPE})
    public @interface MyInterface {}
    

    元注解
    元注解是可以注解到注解上的注解,简单来说就是一种基本注解,可以作用到其他注解上。

    Java中总共有5中元注解:@Retention,@Documented,@Target,@Inherited,@Repeatable。

    @Retention

    用来说明注解的存活时间,有三种取值:
    RetentionPolicy.SOURCE:注解只在源码阶段保留,编译器开始编译时它将被丢弃忽视

    RetentionPolicy.CLASS:注解会保留到编译期,但运行时不会把它加载到JVM中

    RetentionPolicy.RUNTIME:注解可以保留到程序运行时,它会被加载到JVM中,所以程序运行过程中可以获取到它们

    @Target

    指定注解可作用的目标
    ElementType.PACKAGE:可作用在包上
    ElementType.TYPE:可作用在类、接口、枚举上
    ElementType.ANNOTATION_TYPE:可以作用在注解上
    ElementType.FIELD:可作用在属性上
    ElementType.CONSTRUCTOR:可作用在构造方法上
    ElementType.METHOD:可作用在方法上
    ElementType.PARAMETER:可作用在方法参数上
    ElementType.LOCAL_VARIABLE:可作用在局部变量上,例如方法中定义的变量

    @Documented

    这个注解跟文档相关,它的作用是能够将注解中的元素包含到Javadoc中去。

    @Inherited

    Inherited是继承的意思,但并不是注解本身可被继承,而是指一个父类SuperClass被该类注解修饰,那么它的子类SubClass如果没有任何注解修饰,就会继承父类的这个注解。

    @Repeatable

    可重复的意思.
    实例 :准备利用注解和观察者模式 试下一个类似EventBus的事件总线处理机制。
    EventBus 事件模型


    image.png

    具体实现
    MyBus实现类

    public class MyBus {
        private static volatile MyBus myBus;
        //保存带注解的方法
        private Map<Object, List<SubscriberInfo>> cacheMap = new HashMap<>();
        private ExecutorService executorService;
        private Handler handler;
    
        private MyBus() {
            handler = new Handler(Looper.getMainLooper());
            executorService = Executors.newCachedThreadPool();
        }
    
        //单例初始化
        public static MyBus getInstance() {
            if (myBus == null) {
                synchronized (MyBus.class) {
                    if (myBus == null) {
                        myBus = new MyBus();
                    }
                }
            }
            return myBus;
        }
    
        /***
         * 注册方法
         * @param obj
         */
        public void register(Object obj) {
            List<SubscriberInfo> list = cacheMap.get(obj);
            if (list == null) {
                list = findAnnotationMethod(obj);
                cacheMap.put(obj, list);
            }
        }
    
        /**
         * 寻找带注解的方法
         *
         * @param obj
         * @return
         */
        private List<SubscriberInfo> findAnnotationMethod(Object obj) {
            List<SubscriberInfo> list = new ArrayList<>();
            Class<?> clazz = obj.getClass();
            //获取所有的方法
            Method[] methods = clazz.getMethods();
            for (Method method : methods) {
                Subscriber subscriber = method.getAnnotation(Subscriber.class);
                if (subscriber == null) continue;
                checkMethod(method);
                SubscriberInfo subscriberInfo = new SubscriberInfo(method.getParameterTypes()[0], subscriber.threadMode(), method, obj);
                list.add(subscriberInfo);
            }
            return list;
        }
    
        /**
         * 检查方法是否符合规则
         *
         * @param method
         */
        private void checkMethod(Method method) {
            //方法返回必须为void
            if (!TextUtils.equals("void", method.getGenericReturnType().toString())) {
                throw new RuntimeException("method must return void ");
            }
            //方法参数校验
            Class<?>[] paramsTypes = method.getParameterTypes();
            if (paramsTypes.length != 1) {
                throw new RuntimeException("method must has one params");
            }
        }
    
        /**
         * 清除保存的注解
         *
         * @param getter
         */
        public void unRegister(Object getter) {
            if (cacheMap.containsKey(getter)) {
                cacheMap.remove(getter);
            }
        }
    
        /**
         * 发送信息
         *
         * @param send
         */
        public static void post(Object send) {
            Set<Object> set = myBus.cacheMap.keySet();
            for (final Object obj : set) {
                List<SubscriberInfo> subscriberInfos = myBus.cacheMap.get(obj);
                if (subscriberInfos != null) {
                    for (final SubscriberInfo subscriberInfo : subscriberInfos) {
                        //判断这个类是否为SubscriberInfo的子类
                        if (subscriberInfo.type.isAssignableFrom(send.getClass())) {
                            execute(subscriberInfo, send);
                        }
                    }
                }
            }
        }
        //线程调度
        private static void execute(final SubscriberInfo subscriberInfo, final Object send) {
            switch (subscriberInfo.threadMode) {
                case MAIN:
                    if (Looper.getMainLooper() == Looper.myLooper()) {
                        invoke(subscriberInfo, send);
                    } else {
                        myBus.handler.post(new Runnable() {
                            @Override
                            public void run() {
                                invoke(subscriberInfo, send);
                            }
                        });
                    }
                    break;
                case POSTING:
                    invoke(subscriberInfo, send);
                    break;
                case BACKGROUND:
                    if (Looper.getMainLooper() == Looper.myLooper()) {
                        myBus.executorService.execute(new Runnable() {
                            @Override
                            public void run() {
                                invoke(subscriberInfo, send);
                            }
                        });
                    } else {
                        invoke(subscriberInfo, send);
                    }
                    break;
                case ASYNC:
                    myBus.executorService.execute(new Runnable() {
                        @Override
                        public void run() {
                            invoke(subscriberInfo, send);
                        }
                    });
                    break;
            }
    
        }
    
        /**
         * 执行注解方法
         *
         * @param info   方法封装对象
         * @param setter 消息对象的封装
         */
        private static void invoke(SubscriberInfo info, Object setter) {
            try {
                info.method.setAccessible(true);
                info.method.invoke(info.object, setter);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
    

    自定义注解

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface Subscriber {
        /**
         * 在哪个线程执行注解方法
         */
        ThreadMode threadMode() default ThreadMode.POSTING;
    }
    

    枚举线程

    public enum ThreadMode {
        POSTING,//发送者的线程
        MAIN,
        BACKGROUND,
        ASYNC//异步线程
    }
    

    订阅实体类

    /**
     * 订阅对象
     */
    public class SubscriberInfo {
        public Object object;
        //消息类型
        public Class<?> type;
        // 回调线程
        public ThreadMode threadMode;
        //回调方法
        public Method method;
    
    
        public SubscriberInfo(Class<?> type, ThreadMode threadMode, Method method,Object object) {
            this.type = type;
            this.threadMode = threadMode;
            this.method = method;
            this.object = object;
        }
    }
    

    这样就完成了
    最终demo github:https://github.com/525642022/MyBus

    相关文章

      网友评论

        本文标题:android 源码设计模式读书笔记(七)观察者模式+注解

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