EventBus(二)使用反射的方式的原理

系列文章

EventBus(一) 简单使用,不使用反射,使用注解处理器
EventBus(二)使用反射的方式的原理
EventBus(三)手写EventBus3.1.1

提要

按照官网的配置方式,默认就是走的反射的方式实现的,所有有必要将使用反射实现的方式详细学习一下。

思路

注册的时候,将注册的对象object传入,通过反射获取到此对象object所在Class的所有方法, 遍历所有方法,找到@Subscribe注解的方法,经过判断保护,然后将每个有@Subscribe注解的方法分别封装成一个JavaBean对象,此JavaBean对象的字段包括方法的参数类型,线程模式,订阅的方法等信息。然后将注册的对象作为key,List作为值缓存到map中。

发送时间的时候, 将遍历缓存map对象,找到方法参数类型与发送方一致的多个方法,然后判断线程模式,根据不同的线程模式,做不同的逻辑判断,但是最后都是通过反射mathod.invoke方法,来调用注册方的方法。

逻辑思路就是这样,下面是撸码。

线程状态枚举类

public enum ThreadMode {
//事件的处理在和事件的发送在相同的进程
POSTING,
//事件的处理会在UI线程中执行
MAIN ,
//后台进程,处理如保存到数据库等操作
BACKGROUND ,
//异步执行,另起线程操作。事件处理会在单独的线程中执行:主要用于在后台线程中执行耗时操作
ASYNC

}

用于@Subscribe注解中的处理线程
默认为POSTING
主线程发布-主线程接收,子线程发布-子线程接收

订阅方法封装类(JavaBean)


//订阅方法(注解方法)的参数类型
private Class type;
//订阅方法(注解方法)的线程模式
private ThreadMode th readMode ;
//订阅方法(注解方法)
private Method method;

提供构造方法
提供getter / setter方法

收集所有订阅方法

//获取类
Class clazz = getter . getClass();
//获取所有方法
Method[] methods = clazz. getMethods();
//循环方法
for (Method method : methods) {
//获取方法的注解
Subscribe subscribe = method. getAnnotation ( Subscribe.class) ;
//获取订阅方法参数
Class[] parameterTypes = method. getParameterTypes();
//完全符合要求、规范的方法,保存到方法对象中MethodManager (3个重要成员: 方法、参数、线程)
MethodManager manager = new MethodManager (pa rameterTypes[0], subscribe. threadMode(),method);
}


保存到Map cacheMap缓存中

发布事件

//订阅者已经登记,从登记表中找出
Set<0bject> set = cacheMap. keySet();
//比如获取MainActivity对象
for (final 0bject getter : set) {	
	//获取MainAc tivity中所有注解的方法
	List methodL ist = cacheMap . get (getter);
	if (methodList != null) {

	//循环每个方法
	for (final MethodManager method : methodL ist) {
		//通过EventBean来判断是否匹配上
		if (method . getType() . isAssignableF rom( setter . getClass())) {
		//线程调度
		switch ( method . getThreadMode()) {
			case POSTING: 
			//...
			break;
			case MAIN:
			break;
			case BACKGROUND :
			break;
		}
}

总控制类


public class EventBus {

    // volatile修饰的变量不允许线程内部缓存和重排序,即直接修改内存
    private static volatile EventBus instance;
    // 用来保存这些带注解的方法(订阅者的回调方法)
    private Map> cacheMap;

    private Handler handler;
    private ExecutorService executorService;

    private EventBus() {
        cacheMap = new HashMap<>();

        // Handler高级用法:将handler放在主线程使用
        handler = new Handler(Looper.getMainLooper());
        // 创建一个子线程(缓存线程池)
        executorService = Executors.newCachedThreadPool();
    }

    public static EventBus getDefault() {
        if (instance == null) {
            synchronized (EventBus.class) {
                if (instance == null) {
                    instance = new EventBus();
                }
            }
        }
        return instance;
    }

    // 找到MainActivity所有带符合注解的方法
    public void register(Object getter) {
        // 获取MainActivity所有的方法
        List methodList = cacheMap.get(getter);
        if (methodList == null) { // 不为空表示以前注册完成
            methodList = findAnnotationMethod(getter);
            cacheMap.put(getter, methodList);
        }
    }

    // 获取MainActivity中所有注解的方法
    private List findAnnotationMethod(Object getter) {
        List methodList = new ArrayList<>();
        // 获取类
        Class clazz = getter.getClass();
        // 获取所有方法
        Method[] methods = clazz.getMethods();

        // 性能优化。N个父类不可能有自定义注解。排除后再反射
        while (clazz != null) {
            // 找出系统类,直接跳出,不添加cacheMap(因为不是订阅者)
            String clazzName = clazz.getName();
            if (clazzName.startsWith("java.") || clazzName.startsWith("javax.")
                    || clazzName.startsWith("android.")) {
                break;
            }

            // 循环方法
            for (Method method : methods) {
                // 获取方法的注解
                Subscribe subscribe = method.getAnnotation(Subscribe.class);
                // 判断注解不为空,切记不能抛异常
                if (subscribe == null) {
                    continue;
                }
                // 严格控制方法格式和规范
                // 方法必须是返回void(一次匹配)
                Type returnType = method.getGenericReturnType();
                if (!"void".equals(returnType.toString())) {
                    throw new RuntimeException(method.getName() + "方法返回必须是void");
                }
                // 方法参数必须有值(二次匹配)
                Class[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length != 1) {
                    throw new RuntimeException(method.getName() + "方法有且只有一个参数");
                }

                // 完全符合要求、规范的方法,保存到方法对象中MethodManager(3个重要成员:方法、参数、线程)
                MethodManager manager = new MethodManager(parameterTypes[0], subscribe.threadMode(), method);
                methodList.add(manager);
            }

            // 不断循环找出父类含有订阅者(注解方法)的类。直到为空,比如AppCompatActivity没有吧
            clazz = clazz.getSuperclass();
        }
        return methodList;
    }

    // SecondActivity发送消息
    public void post(final Object setter) {
        // 订阅者已经登记,从登记表中找出
        Set set = cacheMap.keySet();
        // 比如获取MainActivity对象
        for (final Object getter : set) {
            // 获取MainActivity中所有注解的方法
            List methodList = cacheMap.get(getter);
            if (methodList != null) {
                // 循环每个方法
                for (final MethodManager method : methodList) {
                    // 有可能多个方法的参数一样,从而都同时收到发送的消息
                    // 通过EventBean来判断是否匹配上
                    if (method.getType().isAssignableFrom(setter.getClass())) {
                        // 通过方法的类型匹配,从SecondActivity发送的EventBean对象(参数)
                        // 匹配MainActivity中所有注解的方法符合要求的,都发送消息

                        // class1.isAssignableFrom(class2) 判定此 Class 对象所表示的类或接口
                        // 与指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口

                        // 线程调度
                        switch (method.getThreadMode()) {
                            case POSTING:
                                invoke(method, getter, setter);
                                break;

                            case MAIN:
                                // 先判断发送方是否在主线程
                                if (Looper.myLooper() == Looper.getMainLooper()) {
                                    invoke(method, getter, setter);
                                } else { // 子线程 - 主线程,切换线程(用到Handler)
                                    handler.post(new Runnable() {
                                        @Override
                                        public void run() {
                                            invoke(method, getter, setter);
                                        }
                                    });
                                }
                                break;

                            case BACKGROUND:
                                // 先判断发送方是否在主线程
                                if (Looper.myLooper() == Looper.getMainLooper()) {
                                    // 主线程 - 子线程,创建一个子线程(缓存线程池)
                                    executorService.execute(new Runnable() {
                                        @Override
                                        public void run() {
                                            invoke(method, getter, setter);
                                        }
                                    });
                                } else { // 子线程 到 子线程,不用切换线程
                                    invoke(method, getter, setter);
                                }
                                break;
                        }
                    }
                }
            }
        }
    }

    // 找到匹配方法后,通过反射调用MainActivity中所有符合要求的方法
    private void invoke(MethodManager method, Object getter, Object setter) {
        Method execute = method.getMethod();
        try {
            execute.invoke(getter, setter);
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

 
  

                            
                        
                    
                    
                    

你可能感兴趣的:(android)