手动做一套自己的RockaIOC

ButterKnife,XUtils,RockaIOC !

定义

AOP

AOP(Aspect Oriented Programming 面向切面编程)技术是建立在JAVA反射和动态代理的基础上的。调用者直接调用的其实AOP容器动态生成的代理对象,再由代理对象调用目标对象完成原始的业务逻辑。

  • 处理核心业务的时候难免会遇到以前相同逻辑的业务处理(Android 动态申请危险权限,Android 网络监测等)这个时候比较常用的就是AOP来进行处理了。

IOC

IOC(Inversion of Control 控制反转)即让调用类对某一接口具体实现类的选择控制权从调用类中移除交给第三方。换一种说法那就是依赖注入即调用类对某一接口实现类的依赖关系由第三方(容器)注入,以移除调用类对某一接口实现类的依赖。

  • 注入方式可以分为三种:构造函数注入、属性注入和接口注入、

注解

自定义注解比较简单,简单解释下就是,注解就像是一种标记,加了注解就像是打了标记,程序可以利用JAVA 的反射机制来了解你的类及各种元素上的标记,在针对不同标记来做对应的事。

1
2
3
4
5
6
7
// RUNTIME 运行时检测,CLASS 编译时, SOURCE 源码资源的时候
@Retention(RetentionPolicy.RUNTIME)
// FIELD 注解只能放在属性上,METHOD 方法上,TYPE 类上,CONSTRUCTOR 构造方法上
@Target(ElementType.FIELD)
public @interface EventViewById {
int value();
}

反射

主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。 反射是java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接,反射使用不当会成本很高。

  • API在:package java.lang.reflect
  • 反射简单用法:
1
2
3
4
5
6
7
//反射获取属性
Class clazz = object.getClass();
Field[] fields = clazz.getDeclaredFields();

//反射获取方法
Class clazz = object.getClass();
Method[] methods = clazz.getDeclaredMethods();

常见IOC框架

XUtils(xutils:3.5.0)

源码解析:

1.单例模式实例化 ViewInjectorImpl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//在Activity或者View中注入Activity实例或者View实例
//x是他的任务控制中心,通过单例进行初始化
x.view().inject(this);

public static ViewInjector view() {
if (Ext.viewInjector == null) {
ViewInjectorImpl.registerInstance();
}
return Ext.viewInjector;
}

public static void registerInstance() {
if (instance == null) {
synchronized (lock) {
if (instance == null) {
instance = new ViewInjectorImpl();
}
}
}
x.Ext.setViewInjector(instance);
}

2.注入Object,通过反射拿到注解,并且拿到注解的值,在设置到属性或者方法中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
@SuppressWarnings("ConstantConditions")
private static void injectObject(Object handler, Class<?> handlerType, ViewFinder finder) {
if (handlerType == null || IGNORED.contains(handlerType)) {
return;
}

// 从父类到子类递归
injectObject(handler, handlerType.getSuperclass(), finder);

// inject view
Field[] fields = handlerType.getDeclaredFields();
if (fields != null && fields.length > 0) {
for (Field field : fields) {

Class<?> fieldType = field.getType();
if (
/* 不注入静态字段 */ Modifier.isStatic(field.getModifiers()) ||
/* 不注入final字段 */ Modifier.isFinal(field.getModifiers()) ||
/* 不注入基本类型字段 */ fieldType.isPrimitive() ||
/* 不注入数组类型字段 */ fieldType.isArray()) {
continue;
}

ViewInject viewInject = field.getAnnotation(ViewInject.class);
if (viewInject != null) {
try {
View view = finder.findViewById(viewInject.value(), viewInject.parentId());
if (view != null) {
//可以操作所有修饰符
field.setAccessible(true);
//反射注入属性
field.set(handler, view);
} else {
throw new RuntimeException("Invalid @ViewInject for "
+ handlerType.getSimpleName() + "." + field.getName());
}
} catch (Throwable ex) {
LogUtil.e(ex.getMessage(), ex);
}
}
}
} // end inject view

// inject event
Method[] methods = handlerType.getDeclaredMethods();
if (methods != null && methods.length > 0) {
for (Method method : methods) {

if (Modifier.isStatic(method.getModifiers())
|| !Modifier.isPrivate(method.getModifiers())) {
continue;
}

//检查当前方法是否是event注解的方法
Event event = method.getAnnotation(Event.class);
if (event != null) {
try {
// id参数
int[] values = event.value();
int[] parentIds = event.parentId();
int parentIdsLen = parentIds == null ? 0 : parentIds.length;
//循环所有id,生成ViewInfo并添加代理反射
for (int i = 0; i < values.length; i++) {
int value = values[i];
if (value > 0) {
ViewInfo info = new ViewInfo();
info.value = value;
info.parentId = parentIdsLen > i ? parentIds[i] : 0;
method.setAccessible(true);
EventListenerManager.addEventMethod(finder, info, event, handler, method);
}
}
} catch (Throwable ex) {
LogUtil.e(ex.getMessage(), ex);
}
}
}
} // end inject event

}

ButterKnife(butterknife:8.8.1)

ButerKnife主要会引入两个module(1个是他的核心实现,1个是他的所有的注解)

简单点就是

1.编译的时候ButterKnifeProcessor 生成 .java –> class文件

2.运行是viewBinder.bind(finder, target, source);

源码解析:

1
2
3
4
5
@NonNull @UiThread
public static Unbinder bind(@NonNull Activity target) {
View sourceView = target.getWindow().getDecorView();
return createBinding(target, sourceView);
}

在点到createBinding()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private static Unbinder createBinding(@NonNull Object target, @NonNull View source) {
Class<?> targetClass = target.getClass();
if (debug) Log.d(TAG, "Looking up binding for " + targetClass.getName());
Constructor<? extends Unbinder> constructor = findBindingConstructorForClass(targetClass);

if (constructor == null) {
return Unbinder.EMPTY;
}

//noinspection TryWithIdenticalCatches Resolves to API 19+ only type.
try {
return constructor.newInstance(target, source);
} catch (IllegalAccessException e) {
throw new RuntimeException("Unable to invoke " + constructor, e);
} catch (InstantiationException e) {
throw new RuntimeException("Unable to invoke " + constructor, e);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
}
if (cause instanceof Error) {
throw (Error) cause;
}
throw new RuntimeException("Unable to create binding instance.", cause);
}
}

createBinding()方法主要就是拿到我们绑定的Activity的Class,然后通过Constructor构造器获取一个Unbinder子类的构造方法,然后在调用newInstance(target, source)通过构造方法获取到Unbinder子类的一个实例,这里传入两个参数,说明构造方法里需要两个参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Nullable @CheckResult @UiThread
private static Constructor<? extends Unbinder> findBindingConstructorForClass(Class<?> cls) {
//见下方
Constructor<? extends Unbinder> bindingCtor = BINDINGS.get(cls);
if (bindingCtor != null) {
if (debug) Log.d(TAG, "HIT: Cached in binding map.");
return bindingCtor;
}
String clsName = cls.getName();
if (clsName.startsWith("android.") || clsName.startsWith("java.")) {
if (debug) Log.d(TAG, "MISS: Reached framework class. Abandoning search.");
return null;
}
try {
//传入要绑定的类名
Class<?> bindingClass = cls.getClassLoader().loadClass(clsName + "_ViewBinding");
//noinspection unchecked
//反射调用构造方法,相当于拿到Class_ViewBinding(通过ButterKnifeProcessor生成)的实例,
bindingCtor = (Constructor<? extends Unbinder>) bindingClass.getConstructor(cls, View.class);
if (debug) Log.d(TAG, "HIT: Loaded binding class and constructor.");
} catch (ClassNotFoundException e) {
if (debug) Log.d(TAG, "Not found. Trying superclass " + cls.getSuperclass().getName());
bindingCtor = findBindingConstructorForClass(cls.getSuperclass());
} catch (NoSuchMethodException e) {
throw new RuntimeException("Unable to find binding constructor for " + clsName, e);
}
BINDINGS.put(cls, bindingCtor);
return bindingCtor;
}
1
2
3
4

//这个BINDINGS数据结构主要保存了Class作为Key,Class_ViewBinding作为Value的目的是提高缓存和bind性能,Class_ViewBinding就是生成的Unbinder的子类。
@VisibleForTesting
static final Map<Class<?>, Constructor<? extends Unbinder>> BINDINGS = new LinkedHashMap<>();

ButterKnife生成类的路径:
Build -> intermediates -> classes -> debug -> com…

在build.gradle文件里可以看到这个自定义注解处理器,项目中是找不到这个文件的
annotationProcessor ‘com.jakewharton:butterknife-compiler:8.8.1’

ButterKnife-Compiler源码地址

手写IOC框架

首先声明自定义注解.

1
2
3
4
5
6
7
8
9
10
11
12

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface EventViewById {
int value();
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface EventOnClick {
int[] value();
}

然后通过反射找到自定义的注入属性并且获取自定义属性上面的值,通过反射将找到的View注入属性中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

/**
* 注入属性
*
* @param viewFinder
* @param object
*/
@android.annotation.TargetApi(24)
private static void injectField(ViewFinder viewFinder, Object object) {
Class clazz = object.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
//获取属性上面的注解值
EventViewById bindViewById = field.getAnnotation(EventViewById.class);
if (bindViewById != null) {
int viewId = bindViewById.value();
View view = viewFinder.findViewById(viewId);
if (view != null) {
try {
//通过反射注入属性
field.setAccessible(true);
field.set(object, view);
} catch (IllegalAccessException ex) {
ex.toString();
}
}
}
}
}

注入事件以及绑定点击事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/**
* 注入事件
*
* @param viewFinder
* @param object
*/
@android.annotation.TargetApi(24)
private static void injectEvent(ViewFinder viewFinder, Object object) {
Class clazz = object.getClass();
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
//获取方法上面的注解值
EventOnClick clickEvent = method.getDeclaredAnnotation(EventOnClick.class);
if (clickEvent != null) {
int[] viewIds = clickEvent.value();
if (viewIds.length > 0) {
for (int viewId : viewIds) {
View view = viewFinder.findViewById(viewId);
boolean isCheckNet = method.getAnnotation(EventCheckNet.class) != null;
if (view != null) {
view.setOnClickListener(new DeclaredOnClickListener(method, isCheckNet, object));
}
}
}
}
}
}

private static class DeclaredOnClickListener implements View.OnClickListener {

private Method mMethod;
private Object mHandlerType;
private boolean mIsNet;

public DeclaredOnClickListener(Method method, boolean isNet, Object object) {
this.mMethod = method;
this.mHandlerType = object;
this.mIsNet = isNet;
}

@Override
public void onClick(View view) {
if (mIsNet) {
if (!isNetworkConnected(view.getContext())) {
Toast.makeText(view.getContext(), "no net", Toast.LENGTH_SHORT).show();
return;
}
}

//通过反射
try {
mMethod.setAccessible(true);
mMethod.invoke(mHandlerType, view);
} catch (Exception e) {
e.printStackTrace();
}
}
}

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器