Android中的注解
Posted ZhangJianIsAStark
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android中的注解相关的知识,希望对你有一定的参考价值。
本篇博客记录一下android中注解的使用方式。
Android使用注解时,需要在build.gradle中导入对应的Library,例如:
dependencies
...........
implementation 'com.android.support:support-annotations:27.0.2'
support-annotations中定义了一系列元注解,
用来帮助开发者在编译期间发现可能存在的Bug。
下面我们记录一下不同类型的注解。
1、Nullness注解
此类注解主要作用于函数参数或者返回值,其中:
@Nullable: 标记参数或者返回值可以为空。
@NonNull: 标记参数或者返回值不可以为空。
当出现违反注解标记的代码时,Android Studio就会给出提示。
同时,利用Android Lint进行静态代码检查时,也会有错误提示。
具体的使用示例类似于:
public void onCreate(@Nullable Bundle savedInstanceState,
@Nullable PersistableBundle persistentState)
onCreate(savedInstanceState);
2、资源类型注解
资源在Android中通常以整型值表示,并保存在R.java中。
这意味着一个需要传入String资源值的函数,如果传入drawable资源值,
不会出现任何编译期错误,只有在执行时才能发现问题。
此时,就可以考虑使用资源类型注解。
资源类型注解作用于函数参数、返回值及类的变量,例如:
@AnimatorRes:标记整形值为android.R.animator类型(属性动画相关)。
@AnimRes:标记整形值为android.R.anim类型(补间动画相关)。
@XmlRes:标记整形值为android.R.xml类型。
基本上所有资源类型,都有对应的注解,此处不一一列举。
具体的使用示例类似于:
@Override
public void setContentView(@LayoutRes int layoutResID)
getDelegate().setContentView(layoutResID);
3、类型定义注解
在Android开发中,整型值不止经常用来代表资源引用值,
而且经常用来代替枚举值。
@IntDef注解可用来创建一个整型类型定义的新注解,例如:
........
public static final int TEST_MODE_ONE = 1;
public static final int TEST_MODE_TWO = 2;
//设置注解的保留策略,此处表示仅在源文件中,不编译进.class文件
@Retention(RetentionPolicy.SOURCE)
//定义注解可以接受的类型
@IntDef(TEST_MODE_ONE, TEST_MODE_TWO)
//新注解名为TestMode
public @interface TestMode
//使用方式类似于元注解
//使用该函数时,若传入0、1就会被警告,必须是TEST_MODE_ONE等
private void setTestMode(@TestMode int testMode)
..............
..........
此外,如果需要支持多个常量的组合,需要显示将IntDef的flag设置为true,
类似于:
........
public static final int TEST_MODE_ONE = 1;
public static final int TEST_MODE_TWO = 2;
@Retention(RetentionPolicy.SOURCE)
//flag置为true时,才是使用组合值
@IntDef(flag = true, value = TEST_MODE_ONE, TEST_MODE_TWO)
public @interface TestMode
private void setTestMode(@TestMode int testMode)
........
................
当flag设置为true时,就可以按照下列方式调用setTestMode且不引起警告:
..........
setTestMode(TEST_MODE_ONE | TEST_MODE_TWO);
..........
4、线程注解
Android应用开发过程中,经常会涉及到多线程的使用,
界面相关操作必须在主线程,而耗时操作则需要放到后台线程中。
线程相关注解有四种:
@UiThread:标记运行在UI线程,对一个应用而言可能存在多个UI线程,
每个UI线程对应不同Activity的主窗口。
@MainThread:标记运行在主线程,一个应用只有一个主线程,
当然主线程也是UI线程。
通常情况下,我们使用@MainThread来注解生命周期相关的函数,
使用@UiThread来注解视图相关的函数。
一帮情况下,@MainThread和@UiThread是可以互换使用的。
@WorkThread:标记运行在后台的线程。
@BinderThread:标记运行在Binder线程。
具体的使用示例类似于AsyncTask中的:
.............
@MainThread
protected void onPreExecute()
@WorkerThread
protected abstract Result doInBackground(Params... params);
..............
5、值范围注解
当函数参数的取值是在一定范围内时,可以使用值范围注解来防止调用者传入错误的参数。
这种类型的注解有以下几种:
@Size:对于类似数组、集合和字符串之类的参数,
可以使用@Size注解来表示这些参数的大小,例如:
//@Size(min=1)表示集合的长度必须大于等于1
public void setNoEmptyString(@Size(min=1) String str)
...........
//@Size(max=2)表示集合的长度必须小于等于2
public void setLenLessThen2String(@Size(max=2) String str)
........
//@Size(2)表示集合的长度必须等于2
public void setLenEquals2String(@Size(2) String str)
.........
//@Size(multiple=2)表示集合的长度必须是2的倍数
public void setLenMulti2String(@Size(multiple=2) String str)
.........
@IntRange和@FloatRange: 限定参数类型及取值范围,例如:
public void setInt(@IntRange(from=0, to=255) int value)
.......
public void setFloat(@FloatRange(from=0.0, to=1.0) float value)
.........
6、权限注解
Android应用在使用某些系统功能时,需要在AndroidManifest.xml中声明权限,
否则在运行时会提示缺失对应的权限。
为了在编译期及时发现缺失的权限,我们可以使用@RequiresPermission注解。
具体的用法类似于:
//表明调用该函数需要声明一个权限
@RequiresPermission(Manifest.permission.CHANGE_NETWORK_STATE)
public void setDataEnable()
..........
//表明调用该函数需要声明集合中至少一个权限
@RequiresPermission(anyOf =
Manifest.permission.CHANGE_NETWORK_STATE, Manifest.permission.INTERNET)
public void setDataEnable()
.........
//表明调用该函数需要声明集合中所有的权限
@RequiresPermission(allOf =
Manifest.permission.CHANGE_NETWORK_STATE, Manifest.permission.INTERNET)
public void setDataEnable()
.........
除了修饰函数外,该注解还可以修饰Intent对应的ACTION字段或ContentProvider对应的Uri,例如:
@RequiresPermission(Manifest.permission.ACCESS_WIFI_STATE)
public static final String ACTION_TEST = "com.zj.test.Wifi";
//对于ContentProvider可能需要读和写这两个操作,对应不同的权限声明
@RequiresPermission.Read(@RequiresPermission("read_permission"))
@RequiresPermission.Write(@RequiresPermission("write_permission"))
public static final Uri TEST_URI = Uri.parse("content://test/info");
7、重写函数注解
如果API允许调用者重写某个函数,但同时要求重写的函数需要调用被重写的函数,
那么可使用@CallSuper注解,例如Activity中的onCreate函数:
@MainThread
@CallSuper
protected void onCreate(@Nullable Bundle savedInstanceState)
..........
8、返回值注解
如果函数需要调用者对返回值做某些处理,
那么可以使用@CheckResult注解来提示开发者。
我们没必要对每个非空返回值的函数都添加这个注解,
该注解的主要目的是让调用者在使用API时,不至于怀疑该函数是否会产生副作用。
例如Bitmap.java中的:
@CheckResult
public Bitmap extractAlpha()
return extractAlpha(null, null);
此外还可以指定警告信息,例如Context.java中的:
//如果调用者没有检查函数的返回值,Android Studio将会给出警告
//警告信息中包含suggest指定的内容
@CheckResult(suggest="#enforcePermission(String,int,int,String)")
@PackageManager.PermissionResult
public abstract int checkPermission(@NonNull String permission, int pid, int uid);
9、测试可见注解
单元测试中,可能需要访问到一些不可见的类、函数或变量,
这时可以使用@VisibleForTesting注解来使其对测试可见。
10、Keep注解
@Keep注解用来标记在Proguard混淆过程中不需要混淆的类或者方法,例如:
public class Test
@Keep
public void test()
..........
至此,注解相关的基本知识介绍完毕。
最后需要说明的是:
如果项目中使用了Annotation Library,并使用Gradle生成aar压缩包,
那么在编译时Android Gradle插件会抽取出注解信息并打包到aar文件中,
以便函数库的调用者正常使用注解信息。
aar包中的annotations.zip文件就是抽取出来的注解信息。
以上是关于Android中的注解的主要内容,如果未能解决你的问题,请参考以下文章
Android 组件化路由组件 ( 构造路由表中的路由信息 )
Android APT注解处理器 ( 配置注解依赖支持的注解类型Java 版本支持 )