创建布局注解类MyContentView.java,代码如下:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface MyContentView {
int value();
}
创建控件注解类MyViewInject.java,代码如下:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyViewInject {
int value();
}
创建处理注解的反射类MyViewUtils.java,代码如下:
public class MyViewUtils {
// 构造方法注入事件
public static void inject(Activity activity) {
injectObject(activity, new ViewFinder(activity));// 实际注入对象的方法
}
//事件注入对象的方法
private static void injectObject(Object obj, ViewFinder viewFinder) {
// 将注解的信息注入到实际方法中,实现布局的初始化,获得实体类
Class clz = obj.getClass();
// 获得clz的注解信息(自定义的注解信息)
MyContentView myContentView = (MyContentView) clz.getAnnotation(MyContentView.class);
// 获取实际的注解是存在的
if (myContentView != null) {
/**布局的注解获取XML布局**/
// 获取注解的值
int value = myContentView.value();
// 获取的内容注入到制定的方法中
try {
// 设置了setContentView的参数(getDeclareMethod不能获取public方法?)
// setContentView方法就是获取XML布局的方法
Method method = clz.getMethod("setContentView",new Class[] { Integer.TYPE });
method.setAccessible(true);//该设置表示无视权限,直接获取
method.invoke(obj, value);//将获取了参数的setContentView方法添加到指定类中
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
/**控件的注解获取XML布局控件**/
// 获取控件的信息,并注入内容,获取所有的的成员Field[]上的MyViewInject,
//要有Declared,可以访问私有的属性
// 可见,控件的创建必须定义成成员变量才可以使用注解方式
Field[] fields = clz.getDeclaredFields();
// 有成员变量,并且数量不是0
if (fields != null && fields.length != 0) {
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
// 获取注解的信息(成员变量上的)
MyViewInject inject = field.getAnnotation(MyViewInject.class);
if (inject != null) {
// 获取实际的内容
int fieldValue = inject.value();
// 自定义方法获取viewFinder,调用findViewById的方法,帮助当前的obj找到控件
View view = viewFinder.findViewById(fieldValue);
if (view != null) {
try {
field.setAccessible(true);// 无视访问权限
field.set(obj, view);// 把他赋值给Field成员变量
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
}
}
// 自定义了,进行找控件
public static class ViewFinder {
private Activity activity;
private View view;
public ViewFinder(Activity activity) {
this.activity = activity;
}
public ViewFinder(View view) {
this.view = view;
}
// id填写进来,把实际的View给返回出去
public View findViewById(int id) {
View view = activity.findViewById(id);
return view;
}
}
}
最后,进行测试,测试类TestViewUtilsActivity.java,代码如下:
@MyContentView(R.layout.activity_test_view_utils)
public class TestViewUtilsActivity extends Activity {
@MyViewInject(R.id.textview_text)
private TextView textView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyViewUtils.inject(this);
textView.setText("测试的数据,注解+反射的方式");
}
}
布局文件中只含有一个文本框,这里不再上代码。