android 注解使用,Android进阶之Annotation(注解)的使用

注解支持的版本

Android support library从19.1版本开始就引入了一个新的注解库。

添加支持注解库依赖项

要在您的项目中启用注解,请向您的库或应用添加 support-annotations 依赖项。

支持注解库是Android 支持库的一部分。要向您的项目添加注解,您必须下载支持存储库并向 build.gradle文件中添加 support-annotations依赖项。

添加支持注解库依赖项

1,打开 SDK 管理器,方法是点击工具栏中的 SDK Manager或者选择 Tools > Android > SDK Manager;

edfc0780a112

SDK Manager

2,点击 SDK Tools 标签;

edfc0780a112

SDK Tools

3,展开 Support Repository 并选中 Android Support Repository 复选框;

4,点击 OK;

5,将以下代码行添加到 build.gradle 文件的 dependencies 块中,向您的项目添加 support-annotations 依赖项:

dependencies { compile 'com.android.support:support-annotations:24.2.0' }

6,Sync Now;

PS:

如果您使用appcompat库,则无需添加support-annotations依赖项。因为 appcompat库已经依赖注解库。

那有关注解的环境配置就已经构建好了,那接下来就是创建自己的注解的时候了。

介绍注解

在实现自己的注解时,我们需要来了解其中两个注解。

@Retention(RetentionPolicy.*)

Retention,保存策略。传入的RetentionPolicy参数有如下三种:

package java.lang.annotation;

/**

* Annotation retention policy. The constants of this enumerated type

* describe the various policies for retaining annotations. They are used

* in conjunction with the {@link Retention} meta-annotation type to specify

* how long annotations are to be retained.

*

* @author Joshua Bloch

* @since 1.5

*/

public enum RetentionPolicy {

/**

* Annotations are to be discarded by the compiler.

*/

SOURCE,

/**

* Annotations are to be recorded in the class file by the compiler

* but need not be retained by the VM at run time. This is the default

* behavior.

*/

CLASS,

/**

* Annotations are to be recorded in the class file by the compiler and

* retained by the VM at run time, so they may be read reflectively.

*

* @see java.lang.reflect.AnnotatedElement

*/

RUNTIME

}

PS:

1,SOURCR:只在*.java源文件的时候有效;

2,CLASS:只在*.java或者*.class中的文件有效,但是在运行环境无效;

3,RUNTIME:包含以上两种,并且运行时也会有效果,一般我们都会选用该参数。

@Target(ElementType.*)

Target,注解的目标类型。传入的ElementType类型有如下几种:

package java.lang.annotation;

/**

* A program element type. The constants of this enumerated type

* provide a simple classification of the declared elements in a

* Java program.

*

*

These constants are used with the {@link Target} meta-annotation type

* to specify where it is legal to use an annotation type.

*

* @author Joshua Bloch

* @since 1.5

*/

public enum ElementType {

/** Class, interface (including annotation type), or enum declaration */

TYPE,

/** Field declaration (includes enum constants) */

FIELD,

/** Method declaration */

METHOD,

/** Formal parameter declaration */

PARAMETER,

/** Constructor declaration */

CONSTRUCTOR,

/** Local variable declaration */

LOCAL_VARIABLE,

/** Annotation type declaration */

ANNOTATION_TYPE,

/** Package declaration */

PACKAGE,

/**

* Type parameter declaration

*

* @since 1.8

* @hide 1.8

*/

TYPE_PARAMETER,

/**

* Use of a type

*

* @since 1.8

* @hide 1.8

*/

TYPE_USE

}

PS:

1,TYPE:作用于接口、类、枚举、注解;

2,FIELD:作用于成员变量(字段、枚举的常量);

3,METHOD:作用于方法;

4,PARAMETER:作用于方法的参数;

5,CONSTRUCTOR:作用于构造函数;

6,LOCAL_VARIABLE:作用于局部变量;

7,ANNOTATION_TYPE:作用于Annotation。例如如下代码:

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.ANNOTATION_TYPE)

public @interface Retention {

RetentionPolicy value();

}

8,PACKAGE:作用于包名;

9,TYPE_PARAMETER:java8新增,但无法访问到;

10,TYPE_USE:java8新增,但无法访问到;

下面做个DEMO,用注解来做以下两件事:

1,查找控件;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

/**

* 根据ID查看View的注解 2017/4/14 08:54

*/

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public @interface FindViewById {

// 使用value命名,则使用的时候可以忽略,否则使用时就得把参数名加上 2017/4/14 08:57

int value();

}

2,设置点击事件;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

/**

* 设置点击事件 2017/4/14 09:20

*/

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public @interface SetOnClickListener {

int id();

String methodName();

}

PS:

1,变量命名,使用value命名,则使用的时候可以忽略,否则使用时就得把参数名加上,所以我在两个注解上分别使用了不同的变量方式,下面使用的时候,大家记得看清楚。

使用自定义注解

1,在布局文件添加Button,如下:

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:id="@+id/btnSay"

android:text="Hello World!" />

2,在Activity中,申明Button变量以及click方法,如下:

@FindViewById(R.id.btnSay)

@SetOnClickListener(id = R.id.btnSay, methodName = "click")

private Button _btnSay;

/**

* 点击事件 2017/4/14 10:00

*/

public void click() {

Toast.makeText(this, "Hello world", Toast.LENGTH_SHORT).show();

}

3,创建注解解析器,代码如下:

import android.app.Activity;

import android.view.View;

import java.lang.annotation.Annotation;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

/**

* Annotation解析 2017/4/14 09:00

*/

public class AnnotationParse {

/**

* 解析 2017/4/14 09:01

* @param target 解析目标

*/

public static void parse(final Activity target) {

try {

Class> clazz = target.getClass();

Field[] fields = clazz.getDeclaredFields(); // 获取所有的字段 2017/4/14 09:34

FindViewById byId;

SetOnClickListener clkListener;

View view;

String name;

String methodName;

int id;

for (Field field : fields){

Annotation[] annotations = field.getAnnotations();

for(Annotation annotation:annotations) {

if (annotation instanceof FindViewById) {

byId = field.getAnnotation(FindViewById.class); // 获取FindViewById对象 2017/4/14 09:10

field.setAccessible(true); // 反射访问私有成员,必须进行此操作 2017/4/14 09:13

name = field.getName(); // 字段名 2017/4/14 09:18

id = byId.value();

// 查找对象 2017/4/14 09:15

view = target.findViewById(id);

if (view != null)

field.set(target, view);

else

throw new Exception("Cannot find.View name is " + name + ".");

} else if (annotation instanceof SetOnClickListener) { // 设置点击方法 2017/4/14 09:59

clkListener = field.getAnnotation(SetOnClickListener.class);

field.setAccessible(true);

// 获取变量 2017/4/14 10:00

id = clkListener.id();

methodName = clkListener.methodName();

name = field.getName();

view = (View) field.get(target);

if (view == null) { // 如果对象为空,则重新查找对象 2017/4/14 09:45

view = target.findViewById(id);

if (view != null)

field.set(target, view);

else

throw new Exception("Cannot find.View name is " + name + ".");

}

// 设置执行方法 2017/4/14 09:55

Method[] methods = clazz.getDeclaredMethods();

boolean isFind = false;

for (final Method method:methods) {

if (method.getName().equals(methodName)) {

isFind = true;

view.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

try {

method.invoke(target);

} catch (Exception e) {

e.printStackTrace();

}

}

});

break;

}

}

// 没有找到 2017/4/14 09:59

if (!isFind) {

throw new Exception("Cannot find.Method name is " + methodName + ".");

}

}

}

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

PS:

上面的注解解析器注释比较详细,仔细看下,应该就可以读懂上面的解析器作用。它大概做了以下几个事情:

a,通过field.getAnnotation(FindViewById.class);反射获得FindViewById注解对象,进而得到我们设置的参数值R.id.btnSay,再通过Target对象去查找控件,并设置;

b,同1,SetOnClickListener也是这样设置,只不过多了一个通过反射获得的方法,并调用的过程;

c,field.setAccessible(true);一定要设置,因为反射访问的是私有成员变量,不设置会报异常;

4,调用

在OnCreate()方法中,如下调用:

// 解析注解 2017/4/14 09:22

AnnotationParse.parse(this);

this._btnSay.setText("CCB"); // 只是做下改变

5,演示效果

edfc0780a112

效果

总结

总上面的注解解析器中,可以看得出来注解Annotation往往是跟反射配合起来使用的,就连Android现在都很多地方使用到了注解,例如AppcompatActivity类:

edfc0780a112

AppcompatActivity

就写框架的人也常说,无反射,不框架,那现在其实也可以说,无反射,不注解。

所以,要想自己有所进阶,学会创建使用自己的Annotaion就是基础中的基础了。

跟着上面的思路走,那么就应该能正常理解并使用Annotation库了.

切记代码中的注释一定要看。

希望能对大家有所帮助,谢谢支持~~~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值