关于通过注解反射实现findViewById(int x);的原理
2016-06-14 19:32
507 查看
先从简单的地方开始说起,
package 通过注解反射;
public class Person {
private int age;
private String name;
public int getAge(){
return age;
}
public String getName(){
return name;
}
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
Person p = new Person();
System.out.println(p.getAge());
System.out.println(p.getName());
}
}
看这个简单的类,有点基础的都知道,会输出0和null。
然后,我会通过注解改变age和name的值
添加了注解后的类就是这样:
package 通过注解反射;
public class Person {
@MyAnnotation(number = 20)
private int age;
@MyAnnotation(string = "小明")
private String name;
public int getAge(){
return age;
}
public String getName(){
return name;
}
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
Person p = new Person();
X.init(p);
System.out.println(p.getAge());
System.out.println(p.getName());
}
}
输入结果如下图:
![](http://img.blog.csdn.net/20160614193514431?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
看看本人定义的注解,
package 通过注解反射;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 注解会在class字节码文件中存在,在运行时可以通过反射获取到
*
*/
@Retention(RetentionPolicy.RUNTIME)
/**
*
1.CONSTRUCTOR:用于描述构造器
2.FIELD:用于描述成员变
3.LOCAL_VARIABLE:用于描述局部变量
4.METHOD:用于描述方法
5.PACKAGE:用于描述包
6.PARAMETER:用于描述参数
7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
*/
@Target(ElementType.FIELD)
public @interface MyAnnotation {
int number() default -1;
String string() default "NULL";
}
关于注解的详细说明,请童鞋们另寻资料。
<span style="white-space:pre"> </span>int number() default -1;
String string() default "NULL";在两个default在之后将会用到。请记住,注解只起到辅助功能,不会真正影响到实际代码。
有留意的童鞋都会在main方法留意到这个
X.init(p);这个也是本章重头戏,这个方法是通过反射得到注解的值,再通过反射给成员变量赋值,看看怎么实现。
public static void init(Object object) throws IllegalArgumentException, IllegalAccessException{
Class clazz = object.getClass();
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
MyAnnotation annotation = field.getAnnotation(MyAnnotation.class);
if (annotation == null) {
return;
}
int number = annotation.number();
String string = annotation.string();
field.setAccessible(true);
if (number != -1) {
field.setInt(object, number);
}
if (!string.equals("NULL")) {
field.set(object, string);
}
}
}
Class clazz = object.getClass();
这句话是得到Class 的对象,此时打印clazz.getSimpleName()会打印出 Person 。
clazz.getDeclaredFields();这一句是得到该类(Person.class)的所有成员变量(无论是否私有)
MyAnnotation annotation = field.getAnnotation(MyAnnotation.class);
if (annotation == null) {
return;
}
得到成员变量上方的注解,如果没有注解则为null,此刻就会返回,不执行下面方法。
int number = annotation.number();
String string = annotation.string();拿到注解定义的2个值,如果成员变量上没有注解,则为默认值。
field.setAccessible(true);
如果是私有成员变量,就要设置才这句话才可以反射。
if (number != -1) {
field.setInt(object, number);
}
if (!string.equals("NULL")) {
field.set(object, string);
}因为每个成员变量只有一个注解,注解上没有用到的值会是默认值,因此会用来判断注解了来个值,然后给成员变量赋值。
这样就实现通过注解给成员变量赋值了。
---------------------------------下面是安卓部分---------------------------------------------------
private static final class ViewHolder {
@ViewInject(R.id.tv_content)
TextView tv_content;
@ViewInject(R.id.vwd)
ViewWithDraged vwd;
@ViewInject(R.id.btn_1)
Button btn1;
@ViewInject(R.id.btn_2)
Button btn2;
public ViewHolder(View view) {
// x.view().inject(this,view);
X.inject(this,view);
}
}有这么一个内部类也是用过注解来绑定id,注释的代码是xUtils的方法,
X.inject(this,view);是博主自己实现的,注解用的也是xUtils的,其实都一样,
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.xutils.view.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {
int value();
int parentId() default 0;
}
看看具体的实现方法:
public static void inject(Object object, View view) {
Class obejctClass = object.getClass();
Class viewClass = view.getClass();
// 获取object的所有成员变量
Field[] fields = obejctClass.getDeclaredFields();
try {
// 通过反射拿到View的findViewById
Method findViewById = viewClass.getMethod("findViewById", int.class);
for (Field field : fields) {
ViewInject annotation = field.getAnnotation(ViewInject.class);
if (annotation!=null){
// 拿到View的子类和对应的id值
// Log.d("X", field.getName() + "-----" + annotation.value());
field.setAccessible(true);
// 相当于view.findViewById(R.id.xxx);
Object invoke = findViewById.invoke(view, annotation.value());
// 相当于 TextView tv = (TextView)view.findViewById();
field.set(object,invoke);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
每个方法的通途都写上注释了。
package 通过注解反射;
public class Person {
private int age;
private String name;
public int getAge(){
return age;
}
public String getName(){
return name;
}
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
Person p = new Person();
System.out.println(p.getAge());
System.out.println(p.getName());
}
}
看这个简单的类,有点基础的都知道,会输出0和null。
然后,我会通过注解改变age和name的值
添加了注解后的类就是这样:
package 通过注解反射;
public class Person {
@MyAnnotation(number = 20)
private int age;
@MyAnnotation(string = "小明")
private String name;
public int getAge(){
return age;
}
public String getName(){
return name;
}
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
Person p = new Person();
X.init(p);
System.out.println(p.getAge());
System.out.println(p.getName());
}
}
输入结果如下图:
看看本人定义的注解,
package 通过注解反射;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 注解会在class字节码文件中存在,在运行时可以通过反射获取到
*
*/
@Retention(RetentionPolicy.RUNTIME)
/**
*
1.CONSTRUCTOR:用于描述构造器
2.FIELD:用于描述成员变
3.LOCAL_VARIABLE:用于描述局部变量
4.METHOD:用于描述方法
5.PACKAGE:用于描述包
6.PARAMETER:用于描述参数
7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
*/
@Target(ElementType.FIELD)
public @interface MyAnnotation {
int number() default -1;
String string() default "NULL";
}
关于注解的详细说明,请童鞋们另寻资料。
<span style="white-space:pre"> </span>int number() default -1;
String string() default "NULL";在两个default在之后将会用到。请记住,注解只起到辅助功能,不会真正影响到实际代码。
有留意的童鞋都会在main方法留意到这个
X.init(p);这个也是本章重头戏,这个方法是通过反射得到注解的值,再通过反射给成员变量赋值,看看怎么实现。
public static void init(Object object) throws IllegalArgumentException, IllegalAccessException{
Class clazz = object.getClass();
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
MyAnnotation annotation = field.getAnnotation(MyAnnotation.class);
if (annotation == null) {
return;
}
int number = annotation.number();
String string = annotation.string();
field.setAccessible(true);
if (number != -1) {
field.setInt(object, number);
}
if (!string.equals("NULL")) {
field.set(object, string);
}
}
}
Class clazz = object.getClass();
这句话是得到Class 的对象,此时打印clazz.getSimpleName()会打印出 Person 。
clazz.getDeclaredFields();这一句是得到该类(Person.class)的所有成员变量(无论是否私有)
MyAnnotation annotation = field.getAnnotation(MyAnnotation.class);
if (annotation == null) {
return;
}
得到成员变量上方的注解,如果没有注解则为null,此刻就会返回,不执行下面方法。
int number = annotation.number();
String string = annotation.string();拿到注解定义的2个值,如果成员变量上没有注解,则为默认值。
field.setAccessible(true);
如果是私有成员变量,就要设置才这句话才可以反射。
if (number != -1) {
field.setInt(object, number);
}
if (!string.equals("NULL")) {
field.set(object, string);
}因为每个成员变量只有一个注解,注解上没有用到的值会是默认值,因此会用来判断注解了来个值,然后给成员变量赋值。
这样就实现通过注解给成员变量赋值了。
---------------------------------下面是安卓部分---------------------------------------------------
private static final class ViewHolder {
@ViewInject(R.id.tv_content)
TextView tv_content;
@ViewInject(R.id.vwd)
ViewWithDraged vwd;
@ViewInject(R.id.btn_1)
Button btn1;
@ViewInject(R.id.btn_2)
Button btn2;
public ViewHolder(View view) {
// x.view().inject(this,view);
X.inject(this,view);
}
}有这么一个内部类也是用过注解来绑定id,注释的代码是xUtils的方法,
X.inject(this,view);是博主自己实现的,注解用的也是xUtils的,其实都一样,
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.xutils.view.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {
int value();
int parentId() default 0;
}
看看具体的实现方法:
public static void inject(Object object, View view) {
Class obejctClass = object.getClass();
Class viewClass = view.getClass();
// 获取object的所有成员变量
Field[] fields = obejctClass.getDeclaredFields();
try {
// 通过反射拿到View的findViewById
Method findViewById = viewClass.getMethod("findViewById", int.class);
for (Field field : fields) {
ViewInject annotation = field.getAnnotation(ViewInject.class);
if (annotation!=null){
// 拿到View的子类和对应的id值
// Log.d("X", field.getName() + "-----" + annotation.value());
field.setAccessible(true);
// 相当于view.findViewById(R.id.xxx);
Object invoke = findViewById.invoke(view, annotation.value());
// 相当于 TextView tv = (TextView)view.findViewById();
field.set(object,invoke);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
Class obejctClass = object.getClass(); Class viewClass = view.getClass();是分别得到Object.class 和 View.class的Class 对象。
每个方法的通途都写上注释了。
相关文章推荐
- 收藏各种技术源码
- Android使用xUtils方便地下载 / xUtils介绍
- xutils相关资料
- andriod中使用xutils出现java.lang.RuntimeException: Unable to start activity ComponentInfo
- 简单使用xUtils-HttpUtils
- xutil3学习笔记系列(一)——view工具之注解设计
- xUtils下载文件时总大小返回-1问题
- Xutils 使用get请求时,连续请求返回数据相同问题的解决
- xUtils 简介
- xUtils ViewUtils 用法
- Xutils3使用心得
- android xutils 框架简要
- Android中如何利用xUtils简单快捷的实现文件下载
- XUtils中的BitmapUtils全注解
- 关于XUtils的DBUtils使用遇到的错误
- 用注解来省略findViewById
- 多线程下载及XUtils框架使用
- XUtils的使用、混淆
- [Android开发]使用XUtils框架出现的问题记
- xUtils的使用总结(动态更新)