自定义Android 注解

来源:互联网 发布:辅助驾驶软件 编辑:程序博客网 时间:2024/05/13 23:28

基础介绍

Java注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。

(1)元注解
元注解是指注解的注解。有@Retention @Target @Document @Inherited这四种。

(2)@Retention: 定义注解的保留策略
@Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到

(3)@Target:定义注解的作用目标
其定义的源码为:
@Target(ElementType.TYPE) //接口、类、枚举、注解
@Target(ElementType.FIELD) //字段、枚举的常量
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法参数
@Target(ElementType.CONSTRUCTOR) //构造函数
@Target(ElementType.LOCAL_VARIABLE)//局部变量
@Target(ElementType.ANNOTATION_TYPE)//注解
@Target(ElementType.PACKAGE) ///包

(4)@Document:说明该注解将被包含在javadoc中

(5)@Inherited:说明子类可以继承父类中的该注解

举个栗子

这个例子实现了一个findViewById功能。
注解

package com.example.basedemo.annotation.diy;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();    /* parent view id */    int parentId() default 0;}

注解处理

package com.example.basedemo.annotation.diy;import android.app.Activity;import android.view.View;import java.lang.reflect.Field;public class ViewUtils {    private ViewUtils() {    }    public static void inject(Activity activity) {        injectObject(activity, new ViewFinder(activity));    }    @SuppressWarnings("ConstantConditions")    private static void injectObject(Object handler, ViewFinder finder) {        Class<?> handlerType = handler.getClass();        // inject view        Field[] fields = handlerType.getDeclaredFields();        if (fields != null && fields.length > 0) {            for (Field field : fields) {                ViewInject viewInject = field.getAnnotation(ViewInject.class);                if (viewInject != null) {                    try {                        View view = finder.findViewById(viewInject.value(), viewInject.parentId());                        if (view != null) {                            field.setAccessible(true);                            field.set(handler, view);                        }                    } catch (Throwable e) {                        e.printStackTrace();                    }                }            }        }    }}
package com.example.basedemo.annotation.diy;import android.app.Activity;import android.view.View;public class ViewFinder {    private Activity activity;    public ViewFinder(Activity activity) {        this.activity = activity;    }    public View findViewById(int id) {        return  activity.findViewById(id);    }    public View findViewById(int id, int pid) {        View pView = null;        if (pid > 0) {            pView = this.findViewById(pid);        }        View view = null;        if (pView != null) {            view = pView.findViewById(id);        } else {            view = this.findViewById(id);        }        return view;    }}

Activity调用

package com.example.basedemo.annotation.diy;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.widget.TextView;import com.example.basedemo.R;public class DIYAnnotationActivity extends AppCompatActivity {    @ViewInject(R.id.textView)    private TextView textView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_annotation);        ViewUtils.inject(this);        textView.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                textView.setText("成功了!");            }        });    }}

布局只有一个textview,这里就不罗列布局了。
——————OK,到这一步你已经成功了————————

——————下面为增加版————————
如果上面的还不够过瘾,想添加上点击事件注解,那也没问题。
定义一个onclick声明

package com.example.basedemo.annotation.diy;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface OnClick {    int[] value();    int[] parentId() default 0;}

然后在ViewUtils里声明多一个方法。这是用了Java的动态代理方法。

public class ViewUtils {    ......省略    public static void inject(Activity activity) {        injectObject(activity, new ViewFinder(activity));        injectEvent(activity);    }    ......省略    private static void injectEvent(final Activity activity) {        Class<? extends Activity> clazz = activity.getClass();        Method[] methods = clazz.getDeclaredMethods();        for (final Method methodY : methods) {            OnClick click = methodY.getAnnotation(OnClick.class);            if (click != null) {                int[] viewId = click.value();                methodY.setAccessible(true);                Object listener = Proxy.newProxyInstance(View.OnClickListener.class.getClassLoader(),                        new Class[]{View.OnClickListener.class}, new InvocationHandler() {                            @Override                            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                                return methodY.invoke(activity, args);                            }                        });                try {                    for (int id : viewId) {                        View v = activity.findViewById(id);                        Method setClickListener = v.getClass().getMethod("setOnClickListener", View.OnClickListener.class);                        setClickListener.invoke(v, listener);                    }                } catch (Exception e) {                    e.printStackTrace();                }            }        }    } }

在activity里面调用(布局自行添加)

    @OnClick(R.id.tb_2)    public void onClick(View v) {        textView.setText("你按了button2");    }

这时候你又发现你又成功了。
————————————————————

—————来来来,继续升级———————
给setcontentview注解
先设置注解

package com.example.basedemo.annotation.diy;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface ContentView {    int value();}

然后设置注解处理

    public static void injectContentView(Object handler){        Class<?> handlerType = handler.getClass();        // inject ContentView        ContentView contentView = handlerType.getAnnotation(ContentView.class);        if (contentView != null) {            try {                Method setContentViewMethod = handlerType.getMethod("setContentView", int.class);                setContentViewMethod.invoke(handler, contentView.value());            } catch (Throwable e) {                e.printStackTrace();            }        }    }

activity里面调用

@ContentView(R.layout.activity_annotation)public class DIYAnnotationActivity extends AppCompatActivity {    @ViewInject(R.id.textView)    private TextView textView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);//        setContentView(R.layout.activity_annotation);        ViewUtils.injectContentView(this);        ViewUtils.inject(this);        textView.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                textView.setText("成功了!");            }        });    }    @OnClick(R.id.tb_2)    public void onClick(View v) {        textView.setText("你按了button2");    }}
原创粉丝点击