Android开发Android开发经验谈Android开发

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

2019-07-25  本文已影响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

上一篇 下一篇

猜你喜欢

热点阅读