Android 中注解的使用

Android Support Library 从 19.1 版本开始引入了一个新的注解库,其中包含了很多的元注解,使用它们修饰我们的代码, 可以让我们提高程序的开发效率,让我们更早的发现问题。以及对代码施以规范,让代码更加有可读性。这篇文章就来简单了解下这些注解,以及其使用。如有错误和遗漏,欢迎留言和补充~

注:现在我们新建项目直接就依赖了 support.appcompat 包,其中已经依赖了 annotations 包。如果你的项目中写如下注解报错,可以添加注解包:

dependencies {implementation 'androidx.annotation:annotation:1.2.0'
}

@IntDef & @StringDef

替代 Java 中枚举的注解,以 @IntDef 为例,定义和使用如下:

 @IntDef({RED, BLUE, YELLOW})

 @Retention(RetentionPolicy.SOURCE)

 public @interface LightColors{};

 public static final int RED = 1;

 public static final int BLUE = 2;

 public static final int YELLOW = 3;

 public void setColor(@LightColors int color){}

  • @interface:声明新的枚举注解类型。
  • @Retention(RetentionPolicy.SOURCE):告知编译器不将枚举的注解数据存储在 .class 文件中。

如果允许常量与标志(例如:|、& 和 ^ 等等)相结合,则我们可以使用 flag 属性,如:

@IntDef(flag = true, value = {RED, BLUE, YELLOW})

使用:

setColor(RED | BLUE);

@Nullable & @NonNull

  • @Nullable:注解的元素可以为 null。
  • @NonNull:注解的元素不可以为 null。

上面的注解可以修饰如下元素:
1,方法参数。如:

@Nullable

private String data;

2,方法的返回值。 如:

 

@Nullable

public String getData(){

 return data;

}

3,成员属性。如:

 public void setData(@Nullable String data){}

当用空的参数传给被 @NonNull 修饰的方法参数的方法时,会给出如下警告提示(编译不会报错):

passing "null" argument to parameter annotated as @NotNull

@FloatRange & @IntRange

@FloatRange 和 @IntRange 是用于限定范围的注解。其中 @FloatRange 是限定 float 类型的,而 @IntRange 是限定 int 类型的。它们同上注解一样,可以修饰方法参数、方法返回值、成员属性。

以 @IntRange 为例,修饰方法参数的定义如下:

public void setAge(@IntRange(from = 1, to = 180) int age){}

如果调用该方法传的参数不在 1 - 180 的范围内, 如:setAge(0),那么编译会直接报如下错:

value must be ≥ 1 and ≤ 180 (was 0)

@Size

@Size 注解的作用是限定长度的,同上注解一样,可以修饰方法参数、方法返回值、成员属性。

  • 限定字符串的长度:
  • public void setData(@Size(4) String data){}

当传入的字符串长度不等于 4 时,编译器会直接报错:

Length must be exactly 4 
  • 限定数组的长度:

  public void setData(@Size(4) int[] data){}

  • 特殊的限定,如限定为 2 的倍数:

  public void setData(@Size(multiple = 2) int[] data){}

限定最小的长度:

@Size(min = 2)

限定最大的长度:

@Size(max = 2)

等同于 @Size(2) 写法:

@Size(value = 2)

@RequiresPermission

该注解作用是表明方法所执行的内容需要权限。如需要单个权限:

 @RequiresPermission(Manifest.permission.CALL_PHONE)

 private void callPhone(String phone){}

需要一组权限:

 @RequiresPermission(allOf = {

 Manifest.permission.READ_EXTERNAL_STORAGE,

 Manifest.permission.WRITE_EXTERNAL_STORAGE})

 public static final void copyFile(String dest, String source) {}

对于 intent 权限,我们可以定义在 intent 操作名称的字符串上:

 @RequiresPermission(android.Manifest.permission.BLUETOOTH)

  public static final String ACTION_REQUEST_DISCOVERABLE =

  "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";

对于需要单独读写权限的内容提供程序的权限,我们可以在 @RequiresPermission.Read 或 @RequiresPermission.Write 注解中包含每个权限要求:

 @RequiresPermission.Read(@RequiresPermission(READ_HISTORY_BOOKMARKS))

 @RequiresPermission.Write(@RequiresPermission(WRITE_HISTORY_BOOKMARKS))

 public static final Uri BOOKMARKS_URI = Uri.parse("content://browser/bookmarks");

如果权限依赖于提供给方法参数的特定值,那么可以对参数本身使用 @RequiresPermission 而不用列出具体的权限,如 startActivity(intent) 方法:

public abstract void startActivity(@RequiresPermission Intent intent, @Nullable Bundle) {...}

当我们使用这种方式(间接权限)时,构建工具将执行数据流分析以检查传递到方法的参数是否具有任何 @RequiresPermission 注解。如:

 Intent intent = new Intent(Intent.ACTION_CALL);

 intent.setData(Uri.parse("tel:1234567890"));

 startActivity(intent);

这里的 startActivity(intent) 就直接报错了:

call requires permission which may be rejected by user: code should explicitly check to see if permission is available (with `checkPermission`) or explicitly handle a potential `SecurityException`

因为 Intent.ACTION_CALL 中标记了权限注解:

 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)

 @RequiresPermission(Manifest.permission.CALL_PHONE)

 public static final String ACTION_CALL = "android.intent.action.CALL";

@CheckResult

@CheckResult 注解是作用于方法上的,作用是检验有没有处理返回值。如果没有处理返回值则会报错。

 @CheckResult

 public String getData(String data) {

   return data.trim();

 }

线程注解

线程注解可以检查某个方法是否从特定类型的线程调用。支持以下线程注解:

  • @MainThread:表示标记的方法只应在主线程调用。如果标记的是一个类,那么该类中的所有方法都应该是在主线程被调用。例:(通常,应用程序的主线程也是 Ui 线程。但是,在特殊情况下,应用程序的主线程可能不是其 Ui 线程)

 @MainThread

 public void deliverResult(D data) { ... }

  • @UiThread:表示标记的方法或构造函数只应该在 Ui 线程上调用。如果标记的是一个类,那么该类中的所有方法都应是在 Ui 线程被调用。例:

 @UiThread

 public abstract void setText(@NonNull String text) {...}

  • @WorkerThread:表示标记的方法只应该在工作线程上调用。如果标记的是一个类,那么该类中的所有方法都应是在一个工作线程上调用。例:

 @WorkerThread

 protected abstract FilterResults performFiltering(CharSequence constraint);

  • @BinderThread:表示标记的方法只应在绑定线程上调用。如果标记的是一个类,那么该类中的所有方法都应是在绑定线程被调用。例:

 @BinderThread

 public BeamShareData createBeamShareData() { ... }

  • @AnyThread:表示可以从任何线程调用带标记的方法。如果标记的是一个类,那么该类中的所有方法都可以从任何线程中调用。例:

 @AnyThread

 public void deliverResult(D data) { ... }

构建工具会将 @MainThread 和 @UiThread 注解视为可以互换,因此,我们可以从 @MainThread 方法调用 @UiThread 方法,反之亦然。不过如果系统应用在不同线程上带有多个试图,Ui 线程可与主线程不同。因此,我们应该使用 @UiThread 标注于应用的视图层次结构关联的方法,使用 @MainThread 仅标注于应用生命周期关联的方法。

资源注解

在 Android 中几乎所有的资源都有其对于的 id,我们在使用的时候可以直接通过 id 来,如:

textView.setText(getResources().getText(R.string.app_name));

但是这样如果没有写指定的资源注解的话就会风险,比如随便传了个 0,那么就会找不到对应的资源。
为了避免由于自己的粗心大意而引发的错误,我们就可以使用资源注解了,如:

 public int getText(@StringRes int id){}

这样当我们调用该方法时,如果传递的参数并不是 String 类型的资源 id,那么编译器就会报错提示。

除了 @StringRes 资源注解外,还有:

  • @IntegerRes:R.integer 类型资源。
  • @AnimatorRes:R.animator 类型资源。
  • @AnimRes:R.anim 类型资源。
  • @ArrayRes:R.array 类型资源。
  • @AttrRes:R.attr 类型资源。
  • @BoolRes:R.bool 类型资源。
  • @ColorRes:R.color 类型资源。
  • @DimenRes:R.dimen 类型资源。
  • @DrawableRes:R.drawable 类型资源。
  • @FractionRes:R.fraction 类型资源。(百分比)
  • @IdRes:R.id 类型资源。
  • @InterpolatorRes:R.interpolator 类型资源。(插值器)
  • @LayoutRes:R.layout 类型资源。
  • @MenuRes:R.menu 类型资源。
  • @PluralsRes:R.plurals 类型资源。(复数)
  • @RawRes:R.raw 类型资源。
  • @StyleableRes:R.styleable 类型资源。
  • @StyleRes:R.style 类型资源。
  • @TransitionRes: R.transition 类型资源。
  • @XmlRes:R.xml 类型资源。
  • @AnyRes:未知资源。(表示自己不知道是什么类型的资源。比如有可能为 R.drawable 也有可能是 R.string。)

@ColorInt

@ColorInt 注解的作用为:限定颜色值。(ARGB:0xAARRGGBB)

 public void setColor(@ColorInt int color) {}

如果直接使用资源 id,则会报错,如下:

setColor(R.color.colorAccent)// 报错

正确的使用是:

setColor(0xFFFF00FF);

如果要使用资源 id,则可以通过 ContextCompat.getColor() 方法来:

setColor(ContextCompat.getColor(context, R.color.colorAccent));

@CallSuper

该注解用于修饰方法,表示重写该方法时必须调用 super 方法。如 onCreate() 方法:

 @CallSuper

 protected void onCreate(Bundle savedInstanceState) {}

重写 onCreate() 方法时,必须调用 super 方法:

super.onCreate(savedInstanceState);

否则报错。

@VisibleForTesting & @Keep

使用 @VisibleForTesting 和 @Keep 注解可以表示方法、类、或字段的可访问性。

  • @VisibleForTesting:该注解只起到一个注释的作用,告诉其他开发者被标记的代码为什么有这么大的可见程度(为了测试方便)。因此,经常用来修饰 public 或 protected,用来修饰 private 并不会报错,但是没有意义。

  • @Keep:标记的指定代码在混淆时不会被混淆。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/140780.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

8年经验之谈 —— 记一次接口压力测试与性能调优!

经验总结 1. 如果总的CPU占用率偏高,且基本都被业务线程占用时,CPU占用率过高的原因跟JVM参数大小没有直接关系,而跟具体的业务逻辑有关。 2. 当设置JVM堆内存偏小时,GC频繁会导致业务线程停顿增多,TPS下降&#xff…

人工智能如何彻底改变移动测试自动化

移动测试自动化在确保移动应用程序的质量和可靠性方面发挥着至关重要的作用。随着移动领域持续快速发展,测试方法需要跟上移动设备日益增长的复杂性和多样性。在过去几年,AI驱动的技术发展极大改变移动测试的自动化程度。特别是去年ChatGPT的横空出世&am…

基于SSM的考研图书电子商务平台的设计与实现

末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:Vue 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目:是 目录…

【机试题】编写一个Java函数,实现批量获取数据的功能

题目:编写一个Java函数,实现批量获取数据的功能(BService.get(List ids))。具体要求如下: 1)提供一个函数BService.get(List ids),支持最多传入100个id; 2)在BService.get((List ids)函数内部&a…

设计模式-中介者模式(Mediator)

设计模式-中介者模式(Mediator) 一、中介者模式概述1.1 什么是中介者模式1.2 简单实现中介者模式1.3 使用中介者模式的注意事项 二、中介者模式的用途三、中介者模式实现方式3.1 使用接口和类的方式3.2 使用抽象工厂模式的方式3.3 使用单例模式的方式 一…

链动2+1模式系统开发之区域代理深度解析

区域代理的保护机制:在链动商城系统里设定的代理有唯一性,每个省只有一个省代,每个市只有一个市代,每个区县只有一个区县代。这样也是保护每个代理的收益权益。 区域代理包含的权益类别:购物奖励折扣;区域实…

Python实现猎人猎物优化算法(HPO)优化XGBoost回归模型(XGBRegressor算法)项目实战

说明:这是一个机器学习实战项目(附带数据代码文档视频讲解),如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 猎人猎物优化搜索算法(Hunter–prey optimizer, HPO)是由Naruei& Keynia于2022年提出的一种最新的…

Marin说PCB之 PCB封装和原理图封装的藕断丝连

最近天气开始降温了,小编我不得不拿出珍藏多年的秋裤穿上了,就是走路不太方便,有点紧啊,可能是当时衣服尺码买小了吧,不可能是我吃胖了,这个绝对不可能。 话说小编我今年属实有点走霉运啊,下班和…

计网自顶向下(Web服务器+UDPping+邮件客户端)

目录 🐖前言 🌼Web服务器(作业1) 🌳过程 🌳解释 🔥代码 🌼UDPping程序(作业2) 🌳过程 🌳解释 Client Server 整体逻辑 🔥代码 🌼邮件客户端(作业…

Sass 最基础的语法

把每个点最简单的部分记录一下,方便自己查找 官方文档链接 Sass 笔记 1. & 父选择器,编译后为父选择器2. : 嵌套属性3. $ 变量3.1 数据类型3.2 变量赋值3.3. 数组3.4. map 4. 算数运算符5. #{}插值语法5.1 可以在选择器或属性名中使用变量5.2 将有引…

SQL对数据进行去重

工作中使用SQL对数据进行处理计算时可能会遇到这样的问题;读取的表数据会有重复,或者我们关注的几个字段的数据会有重复,直接使用原表数据会引起计算结果不准或者做表连接时产生笛卡尔积。 本文记录使用SQL进行数据去重的几种算法。 distinc…

ChineseChess.2023.11.13.01

中国象棋残局模拟器ChineseChess.2023.11.13.01

正交矩阵的定义

对于n阶矩阵A,如果,其中为单位矩阵,为A的转置矩阵,那么就称A为正交矩阵。 对于正交矩阵, 对于正交矩阵,其列向量都是单位向量,行向量都是单位向量

【matlab】KMeans KMeans++实现手写数字聚类

目录 matlab代码kmeans matlab代码kmeans MNIST DATABASE下载网址: http://yann.lecun.com/exdb/mnist/ 聚类 将物理或抽象对象的集合分成由类似特征组成的多个类的过程称为聚类(clustering)。 对于给定N个n维向量x1,…,xN∈Rn,聚类的目标…

亚马逊云科技Zero ETL集成全面可用,可运行近乎实时的分析和机器学习

亚马逊云科技数据库、数据分析和机器学习全球副总裁Swami Sivasubramanian曾指出:“数据是应用、流程和商业决策的核心。”如今,客户常用的数据传输模式是建立从Amazon Aurora到Amazon Redshift的数据管道。这些解决方案能够帮助客户获得新的见解&#x…

通讯协议学习之路(实践部分):SPI开发实践

通讯协议之路主要分为两部分,第一部分从理论上面讲解各类协议的通讯原理以及通讯格式,第二部分从具体运用上讲解各类通讯协议的具体应用方法。 后续文章会同时发表在个人博客(jason1016.club)、CSDN;视频会发布在bilibili(UID:399951374) 本文…

Spring的Redis客户端

如何在Spring中操作redis 在创建springboot项目的时候引入redis的依赖. 在配置文件里指定redis主机的地址和端口,此处我们配置了ssh隧道,所以连接的就是本机的8888端口. 创建一个controller类,注入操作redis的对象. 前面使用jedis,是通过jedis对象里的各种方法来操作redis的,此…

java写一个自动爬取统计局公开数据的程序

在Java中,爬取网站内容的最常用的库是Jsoup。以下是一个简单的爬虫程序示例,它将爬取统计局网站上的公开采集内容: import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.El…

Ionic组件 ion-list ion-list-header

1 ion-list 列表由多行项目组成,这些项目可以包含 text, buttons, toggles, icons, thumbnails等。列表通常包含具有类似数据内容的项目,如 images and text。 列表支持多种交互,包括滑动项目以显示选项、拖动以重新排列列表中的项目以及删除…

MySQL表的增删改查(进阶)

目录 数据库约束 约束的定义 约束类型 null约束 unique:唯一约束 default:默认值约束 primary key:主键约束(重要) foreign key:外键约束(描述两个表之间的关联) 表的设计 一般思路 三大范式 一对一 一对多 ​编辑 多对多 ​编辑 新增 查询 聚合查询 聚合函…