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

关于注解
定义:注解用于为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 事件模型

具体实现
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