Annotations注解(Android)

API开发文档:https://developer.android.com/studio/write/annotations.html

注解

注解是一种元数据, 可以添加到java代码中. 类、方法、变量、参数、包都可以被注解,可用来将信息元数据与程序元素进行关联,注解对注解的代码没有直接影响.

注解库

如果你使用了com.android.support:appcompat-v7库不需要添加额外的依赖。
但是如果你没有使用这个库,也可以额外单独添加注解库。compile ‘com.android.support:support-annotations:xx.xx.xx’。

注解的作用

便于生成文档。
用于编译时的检查。
用于简洁化代码。

一:标准 Annotation

Nullness注解

@Nullable
@NonNull

 /** Add support for inflating the <fragment> tag. **/
    @NonNull
    @Override
    public View onCreateView(String name, @NonNull Context context,
      @NonNull AttributeSet attrs) {
     
      }

资源类型的注解

public abstract void setTitle(@StringRes int resId) { … }

资源类型的注解,有以下几种:

@StringRes
@ColorRes
@AnimationRes
@DimensionRes
@DimensionPixelOffsetRes
@DimensionPixelSizeRes
@BooleanRes
@ColorStateListRes
@DrawableRes
@IntArrayRes
@IntegerRes
@LayoutRes
@MovieRes
@TextRes
@TextArrayRes
@StringArrayRes

Thread 注解

@MainThread

@UiThread

@WorkerThread

@BinderThread

@AnyThread

值约束注释

@IntRange

public void setAlpha(@IntRange(from=0,to=255) int alpha) { … }

@FloatRange

public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {...}

@Size
最大值 (such as @Size(min=2))
最小值(such as @Size(max=2))
限定值 (such as @Size(2))

int[] location = new int[3];
button.getLocationOnScreen(@Size(min=1) location);

Permission 权限注解

对于有些方法可能需要系统的一些权限,但是我们会忘了在Manifest中加入这些权限,导致程序报错。

例如:
单个权限:

@RequiresPermission(Manifest.permission.SET_WALLPAPER)
public abstract void setWallpaper(Bitmap bitmap) throws IOException;```

例如存储卡权限(多个权限)

@RequiresPermission(allOf = {
Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE})
public static final void copyFile(String dest, String source) { …}

对于Intent权限限制,在需要权限的action中添加权限:

@RequiresPermission(android.Manifest.permission.BLUETOOTH)
public static final String ACTION_REQUEST_DISCOVERABLE =
“android.bluetooth.adapter.action.REQUEST_DISCOVERABLE”;

对于ContentProviders 需要区分read和write权限,可以采用[@RequiresPermission.Read ](https://developer.android.com/reference/android/support/annotation/RequiresPermission.Read.html)或者 [@RequiresPermission.Write ](https://developer.android.com/reference/android/support/annotation/RequiresPermission.Write.html)

注解如下:

@RequiresPermission.Read(@RequiresPermission(READ_HISTORY_BOOKMARKS))
@RequiresPermission.Write(@RequiresPermission(WRITE_HISTORY_BOOKMARKS))
public static final Uri BOOKMARKS_URI = Uri.parse(“content://browser/bookmarks“);

直接添加权限:
 [startActivity(Intent)](https://developer.android.com/reference/android/app/Activity.html#startActivity(android.content.Intent))


public abstract void startActivity(@RequiresPermission Intent intent, @Nullable Bundle) {…}“`

《Annotations注解(Android)》

@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@RequiresPermission(Manifest.permission.CALL_PHONE)
public static final String ACTION_CALL = "android.intent.action.CALL";

返回值注解

@CheckResult

 @CheckResult(suggest="#enforcePermission(String,int,int,String)")
public abstract int checkPermission(@NonNull String permission, int pid, int uid);

强制super注解

比如我们写一个基类:

public class Base {
    @CallSuper
    public void test(){
        Log.e("","");
    }
}```

##Typedef 类型注解
 [@IntDef](https://developer.android.com/reference/android/support/annotation/IntDef.html)
 [@StringDef](https://developer.android.com/reference/android/support/annotation/StringDef.html)

IntDef StringDef可以限制传入参数的内容,这在一些固定参数的方法中尤为重要

public abstract class ActionBar {

// Define the list of accepted constants and declare the NavigationMode annotation
@Retention(RetentionPolicy.SOURCE)
@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
public @interface NavigationMode {}

// Declare the constants
public static final int NAVIGATION_MODE_STANDARD = 0;
public static final int NAVIGATION_MODE_LIST = 1;
public static final int NAVIGATION_MODE_TABS = 2;

// Decorate the target methods with the annotation
@NavigationMode
public abstract int getNavigationMode();

// Attach the annotation
public abstract void setNavigationMode(@NavigationMode int mode);

##@keep
 [@Keep](https://developer.android.com/reference/android/support/annotation/Keep.html)
 
一看到这个词肯定第一反应就是跟混淆相关的,没错,这个就是标识该方法被keep出来,当然你也可以在混淆文件中keep



#二:元注解

Override注解的源码

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}“`

元注解就是用来定义注解的注解.其作用就是定义注解的作用范围, 使用在什么元素上等等, 下面来详细介绍.

元注解共有四种
  • @Documented –注解是否将包含在JavaDoc中
  • @Retention –什么时候使用该注解
  • @Target –注解用于什么地方
  • @Inherited – 是否允许子类继承该注解
@Retention

@Retention 保留的范围,默认值为CLASS. 可选值有三种
SOURCE, 只在源码中可用
CLASS, 在源码和字节码中可用
RUNTIME, 在源码,字节码,运行时均可用

  • RetentionPolicy.SOURCE – 在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。@Override, @SuppressWarnings都属于这类注解。
  • RetentionPolicy.CLASS – 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式。
  • RetentionPolicy.RUNTIME – 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。
@Target

@Target 可以用来修饰哪些程序元素,如 TYPE, METHOD, CONSTRUCTOR, FIELD, PARAMETER等,未标注则表示可修饰所有

  • 取值(ElementType)有:

1.CONSTRUCTOR:用于描述构造器
2.FIELD:用于描述域
3.LOCAL_VARIABLE:用于描述局部变量
4.METHOD:用于描述方法
5.PACKAGE:用于描述包
6.PARAMETER:用于描述参数
7.TYPE:用于描述类、接口(包括注解类型) 或enum声明

@Inherited

@Inherited 是否可以被继承,默认为false

@Documented

@Documented 是否会保存到 Javadoc 文档中

其中, @Retention是定义保留策略, 直接决定了我们用何种方式解析. SOUCE级别的注解是用来标记的, 比如Override, SuppressWarnings. 我们真正使用的类型是CLASS(编译时)和RUNTIME(运行时)

三:自定义注解

自定义 Annotation 表示自己根据需要定义的 Annotation,定义时需要用到上面的元 Annotation
这里是一种分类而已,也可以根据作用域分为源码时、编译时、运行时 Annotation

使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。

定义注解格式:

public @interface 注解名 {定义体}

注解参数的可支持数据类型:

1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)
2.String类型
3.Class类型
4.enum类型
5.Annotation类型
6.以上所有类型的数组

Annotation类型里面的参数该怎么设定:
  • 第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型;
  • 第二,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;
  • 第三,如果只有一个参数成员,最好把参数名称设为”value”,后加小括号.例:下面的例子FruitName注解就只有一个参数成员。
注意:
  • 注解可以设定初始值,使用default就可以实现。
  • 注解只有一个元素的时候,该元素名称必须是value,并且在使用该注解的时候可以省略”alue=”。

  • 注解的值必须是确定的,且不能使用null作为值。

  • 注解可能的类型:所有基本类型、String、Class、enum、Annotation、以上类型的数组形式。

  • 举个例子

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TestAnnotation {
    String value();
    String[] value2() default "value2";
}```

元注解的的意义参考上面的讲解, 不再重复, 这里看注解值的写法:

类型 参数名() default 默认值;
其中默认值是可选的, 可以定义, 也可以不定义
* 自己写的例子:
自定义一个注解:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ ElementType.METHOD ,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
String isAop() default “false”;
}

通过反射机制获取:

public class TestProcess {

public static void process(String str) throws ClassNotFoundException {

    Class clazz = Class.forName(str);

    Annotation[] annotations = clazz.getAnnotations();

    for (Annotation annotation : annotations) {
        System.out.println(annotation.);
    }
}

}

测试使用:

@Test(isAop = “false”)

public class UseTest {
public static void main(String[] args) {
try {
TestProcess.process(“Test”);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}




###参考链接:
>[公共技术点之 Java 注解 Annotation](http://a.codekk.com/detail/Android/Trinea/%E5%85%AC%E5%85%B1%E6%8A%80%E6%9C%AF%E7%82%B9%E4%B9%8B%20Java%20%E6%B3%A8%E8%A7%A3%20Annotation)
[[自定义注解定义和使用](http://blog.csdn.net/u012150370/article/details/47304435)](http://blog.csdn.net/u012150370/article/details/47304435)
    原文作者:流水潺湲
    原文地址: https://www.jianshu.com/p/1eefedd300a3
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞