1,IOC:控制反转,不是一门技术,而是一种思想,IOC有一个专门的容器来创建这些对象,然后给需要的对象使用,这种由容器来帮忙创建及注入依赖的方式叫控制反转,就是本来有自己创建的依赖变成别人创建给你直接使用,所以说反转了
2,定义一个注解是通过@interface来定义,注解只能定义方法
3,注解两大元素:@Target 与@Retention;
@Target:定义我们的注解的目标是什么,通过ElementType来控制,常用的三个属行:TYPE(注解类)FIELD(字段)METHOD(方法)ANNOYTATION_TYPE(定义注解使用)
@Retention:定义存活时间,SOURCE(源码阶段)CLASS(编译期)RUNTIME(存活到运行期)
4,实现layout注入:
//创建inject类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectLayout {
int value();
}
//注入类实现方法
/**
* setContentView方法
* @param obj
*/
private static void injectLayout(Object obj) {
//反射需要先获取Class对象
//首先通过getClass来获取class对象
Class<?> aClass = obj.getClass();
//通过Class的getAnnotation 来获取inject的注解对象对象
InjectLayout annotation = aClass.getAnnotation(InjectLayout.class);
// 判断注解对象是否为空,因为有可能没有InjectLayout的注解
if (annotation!=null){
// 通过注解对象获取到传入的文件ID
int value = annotation.value();
try {
//通过getMethod来setContentView获取方法
Method method = aClass.getMethod("setContentView", int.class);
// 通过invoke来给方法赋值
method.invoke(obj,value);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
//activity使用
@InjectLayout(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {
实现控件的注入
//创建注入类
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectView {
int value();
}
//实现方法
/**
* 成员变量的方法依赖
* @param obj
*/
private static void injectView(Object obj) {
//首先获取class
Class<?> aClass = obj.getClass();
//因为成员变量有多个,所以我们通过getDeclaredFields来获取所有的成员变量
Field[] declaredFields = aClass.getDeclaredFields();
// 通过遍历成员变量来获取变量的依赖注入类
for (Field field:declaredFields){
InjectView injectView = field.getAnnotation(InjectView.class);
// 因为有对象没有注入的对象,所以通过判空的方式判断是否需要
if (injectView!=null){
// 获取到控件ID
int value = injectView.value();
try {
//通过class的getMethod来获取findViewById的方法对象
Method method = aClass.getMethod("findViewById", int.class);
//给对象赋值,到此实现了findViewById的代码,但是我们还需要将它赋值给我们的成员变量
Object view = method.invoke(obj, value);
//设置作用域
field.setAccessible(true);
//给成员变量赋值
field.set(obj,view);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
//activity使用
@InjectView(R.id.btn1)
private Button btn1;
方法注入:因为方法可能有多个;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@InjectEvent(listenerSetter = "setOnClickListener",listener = View.OnClickListener.class,callBack = "onClick")
public @interface InjectOnClick {
//因为方法的传参可能不止一个控件,所以返回值使用数组
int[] value();
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@InjectEvent(listenerSetter = "setOnLongClickListener",listener = View.OnLongClickListener.class,callBack = "onLongClick")
public @interface InjectOnLongClick {
//因为方法的传参可能不止一个控件,所以返回值使用数组
int[] value();
}
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectEvent {
// btn1.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View view) {
// Log.e("whf","btn1_onclick");
// }
// });
//监听方法名
String listenerSetter();
//监听类
Class listener();
// 监听的回调方法名
String callBack();
}
因为不确定传入是点击还是长按事件,对应的Class不确定,所以需要设置代理需要用到InvocationHandler
public class ListenerInvocationHandler implements InvocationHandler {
private Object object;
private Method myMethod;
public ListenerInvocationHandler(Object object, Method myMethod) {
this.object = object;
this.myMethod = myMethod;
}
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
//可以判断是否使用这个方法
return myMethod.invoke(object,objects);
}
}
private static void injectEvent(Object obj) {
//获取class
Class<?> aClass = obj.getClass();
//首先获取class所有的方法,因为可能不止一个方法注释
Method[] declaredMethods = aClass.getDeclaredMethods();
//循环遍历方法,判断该方法是否有注入
for (Method method:declaredMethods){
//方法的注入可能不止一个,所以我们获取所有的注入类,进行循环判断
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation:annotations){
/* //有一种傻瓜式方式实现,了解就好,不建议使用
if (annotation.annotationType().getSimpleName().equals("111")){
}else if (annotation.annotationType().getSimpleName().equals("222")){
}*/
//获取annotation的class对象
Class<? extends Annotation> annotationType = annotation.annotationType();
//我们可以通过定义注解的方式来处理不同的事件
InjectEvent injectEvent = annotationType.getAnnotation(InjectEvent.class);
// 获取监听的方法名,需要传入的对象,callback
String listenerSetter = injectEvent.listenerSetter();
Class listener = injectEvent.listener();
String callBack = injectEvent.callBack();
try {
ListenerInvocationHandler listenerInvocationHandler = new ListenerInvocationHandler(obj, method);
Object proxyInstance = Proxy.newProxyInstance(listener.getClassLoader(),
new Class[]{listener}, listenerInvocationHandler);
//因为我们的value是子类的方法,我们接收的对象是Annotation,无法通过annotation。value()来获取对象,所以我们通过class的getMethod方法来获取
Method valueMethod = annotationType.getMethod("value");
// 通过方法的invoke方法来获取值
int[] ids = (int[]) valueMethod.invoke(annotation);
for (int id:ids){
// 通过class的findViewById方法来获取view
//通过class的getMethod来获取findViewById的方法对象
Method findViewById = aClass.getMethod("findViewById", int.class);
//给对象赋值,到此实现了findViewById的代码,但是我们还需要将它赋值给我们的成员变量
Object view = findViewById.invoke(obj, id);
// 通过view的getMethod 获取需要设置的method方法
Method setterMethod = view.getClass().getMethod(listenerSetter, listener);
setterMethod.setAccessible(true);
setterMethod.invoke(view,proxyInstance);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
activity使用:
@InjectOnClick({R.id.btn1,R.id.btn2})
public void whfOnClick(View view) {
Log.e("whf","whfOnClick");
}
@InjectOnLongClick({R.id.btn1,R.id.btn2})
public boolean whfOnLongClick(View view) {
Log.e("whf","whfOnLongClick");
return false;
}
源码下载地址:https://download.csdn.net/download/feng_zhongsha/16636507?spm=1001.2014.3001.5501