背景知识:
1、注解是当作修饰符来使用的,注解能且仅能写在那些可以写修饰符(诸如public、static之类)的地方。
2、注释必须通过一个注释接口@interface来定义
3、有些元注释是系统定义的例如@Target,这些元注释是为了开发自定义注释而存在的。
例子:
MainActivity.java
package com.thinking.marktest;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity {
private Button btn_test = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_test = findViewById(R.id.btn_test);
try {
AddClickListenerTestHandler.process(this);
} catch (Exception e) {
e.printStackTrace();
}
}
@AddClickListenerTestMark(source = "btn_test")
public void marked_func(View view) {
Log.i("yuyong", "marked_func-->" + view.toString());
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btn_test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="test" />
</LinearLayout>
AddClickListenerTestMark.java
package com.thinking.marktest;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by Yu Yong on 2018/3/26.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AddClickListenerTestMark {
String source();
}
AddClickListenerTestHandler.java
package com.thinking.marktest;
import android.view.View;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* Created by Yu Yong on 2018/3/26.
*/
public class AddClickListenerTestHandler {
public static void process(final Object mainObject) throws Exception {
Class<?> cl = mainObject.getClass();//com.thinking.marktest.MainActivity
for (final Method marked_method : cl.getDeclaredMethods()) {
//method --> marked_func
AddClickListenerTestMark mark = marked_method.getAnnotation(AddClickListenerTestMark.class);
if (mark != null) {
//markObj --> @com.thinking.marktest.AddClickListenerTestMark(source=btn_test)
final Field f_marked_obj = cl.getDeclaredField(mark.source());//Field of btn_test
f_marked_obj.setAccessible(true);
Object marked_obj = f_marked_obj.get(mainObject);//btn_test
Object listener = Proxy.newProxyInstance(null, new Class[]{View.OnClickListener.class}, new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
//Object o --> btn_test
//Method method --> void onClick(View view)
//objects --> View view
return marked_method.invoke(mainObject, objects);
}
});
Method setOnClickListener = marked_obj.getClass().getMethod("setOnClickListener", View.OnClickListener.class);
setOnClickListener.invoke(marked_obj, listener);
}
}
}
}