IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android Annotation注解详解 -> 正文阅读

[移动开发]Android Annotation注解详解

转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/119874435
本文出自【赵彦军的博客】

Java注解

Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。
Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc 不同,Java 标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 当然它也支持自定义 Java 标注。

Java内置了多种标准注解,其定义在java.lang中。

  • Override 表示当前的方法定义将覆盖父类中的方法
    在这里插入图片描述

  • Deprecated 被此注解标记的元素表示被废弃
    在这里插入图片描述

  • SuppressWarnings 关闭不当的编译器警告信息
    在这里插入图片描述
    在上面我们看到了 @Target 、@Retention , 这些也是注解,我们暂且可以称之为注解的注解。

元注解说明

@Retention

表示需要在什么级别保留该注解信息

  • RetentionPolicy.SOURCE:只在源代码中保留 一般都是用来增加代码的理解性或者帮助代码检查之类的,比如我们的Override
  • RetentionPolicy.CLASS : 默认的选择,能把注解保留到编译后的字节码class文件中,仅仅到字节码文件中,运行时是无法得到的
  • RetentionPolicy.RUNTIME :注解不仅能保留到class字节码文件中,还能在运行通过反射获取到,这也是我们最常用的

@Target

表示该注解可以用在什么地方

  • ElementType.FIELD : 能修饰成员变量
  • ElementType.METHOD:能修饰方法
  • ElementType.CONSTRUCTOR : 能修饰构造器
  • ElementType.PACKAGE : 能修饰包
  • ElementType.PARAMETER : 能修饰方法参数
  • ElementType.TYPE : 能修饰类、接口或枚举类型
  • ElementType.ANNOTATION_TYPE : 能修饰注解
  • ElementType.LOCAL_VARIABLE:能修饰局部变量
  • ElementType.MODULE :

通过反射获取注解信息

Annotation是被动的元数据,永远不会有主动行为,所以我们需要通过使用反射,才能让我们的注解产生意义。

首先我们定义一个端口注解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Port {
    String value() default "8080";
}

RetentionPolicy.RUNTIME 在运行时保留注解,作用于是字段。

反射获取字段

object BindPort {

    /**
     * 绑定的目的
     * 1、通过反射获取注解的值
     * 2、通过反射给目标设置值
     */
    fun bind(activity: Activity) {
        //获取所有字段
        val fields = activity.javaClass.declaredFields
        fields.forEach { field ->
            //获取所有注解
            val ans = field.annotations
            ans.forEach {
                if (it is Port) {
                    //获取注解值
                    var port = it.value

                    //通过属性反射给属性注入值
                    field.isAccessible = true
                    field.set(activity, port)
                }
            }
        }
    }

}

上面代码的逻辑很简单:

首先遍历循环所有的属性,如果当前属性被指定的注解所修饰,那么就将当前属性的值修改为注解中成员变量的值。

这里setAccessible(true)的使用时因为,我们在声明port变量时,其类型为private,为了确保可以访问这个变量,防止程序出现异常。

注解的使用:


class MainActivity : AppCompatActivity() {

    @Port
    var port: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        Log.d("yy--", "反射前:$port")

        BindPort.bind(this)

        Log.d("yy--", "反射后:$port")

    }
}

运行结果:

com.example.myapplication D/yy--: 反射前:null
com.example.myapplication D/yy--: 反射后:8080

当然,我们也可以在注解时,自定义我们的属性值,比如:

class MainActivity : AppCompatActivity() {

    @Port("8090")
    var port: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        Log.d("yy--", "反射前:$port")

        BindPort.bind(this)

        Log.d("yy--", "反射后:$port")

    }
}

运行结果:

com.example.myapplication D/yy--: 反射前:null
com.example.myapplication D/yy--: 反射后:8090

方法使用注解

我们来模拟一个http请求, 定义一个 Request 注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Request {

    Method value();

    enum Method {
        GET, POST
    }
}

注解的方式简单,@Retention(RetentionPolicy.RUNTIME) 在运行时保留,@Target(ElementType.METHOD) 作用域在方法上。

下面我们编写,反射的方法,定义 HttpBind

object HttpBind {

    /**
     * 绑定的目的
     * 1、通过反射获取注解的值
     * 2、通过反射给目标设置值
     */
    fun bind(activity: Activity) {
        //获取所有方法
        val methods = activity.javaClass.methods
        methods.forEach { method ->
            //获取所有注解
            val ans = method.annotations
            ans.forEach {
                if (it is Request) {
                    //获取注解值
                    var requestMethod = it.value
                    if (requestMethod == Request.Method.GET) {
                        //发起get请求
                        method.invoke(activity, requestMethod.name)
                    } else if (requestMethod == Request.Method.POST) {
                        //发起post请求
                        method.invoke(activity, requestMethod.name)
                    }
                }
            }
        }
    }

}

注解使用

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //使用反射,解析注解
        HttpBind.bind(this)
    }

    @Request(Request.Method.GET)
    fun http(method: String) {
        Log.d("yy--", "网络请求:$method")
    }
}

我们运行一下,看看效果

D/yy--: 网络请求:GET

方法的参数使用注解

先定义一个参数注解 Path

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Path {
    String value() default "";
}

这个注解也很简单,在运行时保留,作用域在参数上

下面我们使用反射来获取参数注解的值

object HttpBind {

    /**
     * 绑定的目的
     * 1、通过反射获取注解的值
     * 2、通过反射给目标设置值/反射调用方法
     */
    fun bind(activity: Activity) {
        //获取所有方法
        val methods = activity.javaClass.methods
        methods.forEach { method ->
            //获取所有参数注解,一个方法有多个参数,一个参数有多个注解,所以类型是二维数组
            val ans = method.parameterAnnotations
            ans.forEach { annotationArray ->
                annotationArray.forEach { parameterAnnotation ->
                    if (parameterAnnotation is Path) {
                        var parameter = parameterAnnotation.value
                        method.invoke(activity, parameter)
                    }
                }
            }
        }
    }
}

使用如下:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        HttpBind.bind(this)
    }

    fun http(@Path("zhaoyanjun") user: String) {
        Log.d("yy--", "参数注解:$user")
    }
}

运行结果如下:

D/yy--: 参数注解:zhaoyanjun

Android 自带的注解

Android 系统已经帮我内置了很多有用的注解,在我们的开发过程中可以很方便的使用。

 implementation 'androidx.annotation:annotation:1.2.0'

示例如下
在这里插入图片描述
我们举几个常见的例子:

资源限制类

  • @AnimatorRes :animator资源类型
  • @AnimRes:anim资源类型
  • @AnyRes:任意资源类型
  • @ArrayRes:array资源类型
  • @AttrRes:attr资源类型
  • @BoolRes:boolean资源类型
  • @ColorRes:color资源类型
  • @DimenRes:dimen资源类型。
  • @DrawableRes:drawable资源类型。
  • @FractionRes:fraction资源类型
  • @IdRes:id资源类型
  • @IntegerRes:integer资源类型
  • @InterpolatorRes:interpolator资源类型
  • @LayoutRes:layout资源类型
  • @MenuRes:menu资源类型
  • @PluralsRes:plurals资源类型
  • @RawRes:raw资源类型
  • @StringRes:string资源类型
  • @StyleableRes:styleable资源类型
  • @StyleRes:style资源类型
  • @TransitionRes:transition资源类型
  • @XmlRes:xml资源类型

线程限制类

Thread annotations 线程执行限制类:用于限制方法或者类必须在指定的线程执行。如果方法代码运行线程和标注的线程不一致,则会导致警告。

  • @AnyThread
  • @BinderThread
  • @MainThread
  • @UiThread
  • @WorkerThread

数值限制类

Value Constraint Annotations 类型范围限制类:用于限制标注值的值范围

  • @FloatRang
  • @IntRange

LayoutRes

这个是 layout资源类型,我们看一下 Activity 的 setContentView 源码:

    @Override
    public void setContentView(@LayoutRes int layoutResID) {
        getDelegate().setContentView(layoutResID);
    }

本质上,layoutResID 是一个 int 类型,如果不做限定的话,可以传入任意整形,但是有 @LayoutRes 注解的限制,值只能传入 R.layou.xx , 如果传入其他的类型就会报错。举例如下:
在这里插入图片描述
需要注意的是,报错只是编译器的检查出错,提醒开发者改正错误用法,提前规避风险,并不影响编译运行

@MainThread

限定方法执行的线程,如果方法代码运行线程和标注的线程不一致,不会报错,更多是起一个提醒作用

  @MainThread
   fun run() {

  }
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-08-25 12:19:37  更:2021-08-25 12:19:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年3日历 -2025/3/4 12:07:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码