++如果没有基础的同学必须先看我前面的java动态代理模式和java注解基础和java反射总结这几篇文章++
分析
注解起到一个规范作用&获取值得作用,那么值拿到之后就需要操作值,怎么操作呢?当然通过反射,所以接下来就看如何搞。我们从最熟悉的调用开始展开。
特殊说明 |
---|
其中Class,Constructor,Field,Method,Package都实现了AnnotatedElement接口 |
该接口有如下几个方法为核心 |
//如果存在这样的注解,则返回该元素的指定类型的注解,否则为空。
<T extends Annotation> T getAnnotation(Class<T> annotationClass)
//返回该程序元素上存在的所有注解。
Annotation[] getAnnotations()
//判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false.
boolean is AnnotationPresent(Class<?extends Annotation> annotationClass)
//返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。
Annotation[] getDeclaredAnnotations()
实战
自定义注解的话我们需要用项目说话,话不多说
@ContentView(R.layout.activity_main)//布局注解
public class MainActivity extends AppCompatActivity {
@ViewInject(R.id.btn)//控件注解
private Button btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Injector.inject(this);//注册注解
btn.setText("改变按钮文本");
}
@OnClick({R.id.btn})//事件注解
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn:
Toast.makeText(this, "Button OnClick", Toast.LENGTH_SHORT).show();
break;
}
}
}
ContentView
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ContentView {
int value();
}
EventBase
/**
* 事件注解的基本。如果你需要自行扩展各种事件,如点击事件、选项改变事件等,在该注解上加上此注解。
*/
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EventBase {
String listenerSetter();
Class<?> listenerType();
String callbackMethod();
}
OnClick
/**
* 点击事件注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@EventBase(listenerSetter = "setOnClickListener", listenerType = View.OnClickListener.class , callbackMethod = "onClick")
public @interface OnClick {
int[] value();
}
注册器
/**
* 注射器
*/
public class Injector {
public static void inject(Activity activity) {
try {
injectContentView(activity);
injectViewInject(activity);
injectEvents(activity);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void injectContentView(Activity activity) {
Class a = activity.getClass();
if (!a.isAnnotationPresent(ContentView.class)) return;//判断ContentView注解是不是在该类上面
ContentView contentView = (ContentView) a.getAnnotation(ContentView.class);
int layoutId = contentView.value();//得到注解的值
try {
Method method = a.getMethod("setContentView", int.class);//得到setContentView方法
method.setAccessible(true);//设置任意权限可用
method.invoke(activity, layoutId);//执行
} catch (Exception e) {
e.printStackTrace();
}
}
private static void injectViewInject(Activity activity) {
Class a = activity.getClass();
Field[] fields = a.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(ViewInject.class)) {
ViewInject viewInject = field.getAnnotation(ViewInject.class);
int viewId = viewInject.value();
try {
Method method = a.getMethod("findViewById", int.class);
method.setAccessible(true);
Object resView = method.invoke(activity, viewId);//得到控件
field.setAccessible(true);
field.set(activity, resView);//设置给activity对象的值是findViewById得到的值相当于(Button btn = findViewById(R.id.btn);)
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
private static void injectEvents(Activity activity) {
Class a = activity.getClass();
Method[] methods = a.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(OnClick.class)) {
OnClick onClick = method.getAnnotation(OnClick.class);
int[] viewIds = onClick.value();//R.id.btn ...
EventBase eventBase = onClick.annotationType().getAnnotation(EventBase.class);
String methodName = eventBase.callbackMethod();//onClick
String listenerSetter = eventBase.listenerSetter();//setOnClickListener
Class<?> listenerType = eventBase.listenerType();//View.OnClickListener
DynamicHandler handler = new DynamicHandler(activity);
Object listener = Proxy.newProxyInstance(listenerType.getClassLoader(),new Class<?>[] { listenerType } /*listenerType.getInterfaces()*/, handler);//代理View.OnClickListener
handler.addMethod(methodName, method);//将onClick添加到动态代理里面的容器
for (int viewId : viewIds) {
try {
Method findViewByIdMethod = a.getMethod("findViewById", int.class);
findViewByIdMethod.setAccessible(true);
View view = (View) findViewByIdMethod.invoke(activity, viewId);//得到Button这个View
Method setEventListenerMethod = view.getClass().getMethod(listenerSetter, listenerType);//btn.setOnClickListener(View.OnClickListener listener);
setEventListenerMethod.setAccessible(true);
setEventListenerMethod.invoke(view, listener);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}