Android自定义注解(一)

简介: 为什么要写这个,因为前段时间看了一下AOP相关的一些内容,然后也是太久没写注解,看得有点那啥不顺畅,所以想对注解做个总结。一.JAVA自带的注解(1)Override 覆盖(2)Deprecated 标记过期方法(3)SuppressWarnings 屏蔽警告二.

为什么要写这个,因为前段时间看了一下AOP相关的一些内容,然后也是太久没写注解,看得有点那啥不顺畅,所以想对注解做个总结。

一.JAVA自带的注解

(1)Override 覆盖
(2)Deprecated 标记过期方法
(3)SuppressWarnings 屏蔽警告

二.自定义注解

1.定义

我这里写个demo自定义一个注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface BindView {
    int value() default -1;
}

可以看出注解用@interface来标志。

2.元注解

可以看出在上边的定义中,上面还有两个注解,这些被称为元注解,什么是元注解,简单来说就是描述注解的注解
还有什么元数据的,元什么什么的,这个元其实不太好解释,我记得之前看过一个元数据的描述,英文是 data about data,这个元有这个about的那种感觉

元注解有4种
(1)@Retention 用来描述周期,Retention 有“保持时间”的意思,这个属性可以选三个值
SOURCE表示只在源码中有用,编译就没用了。
CLASS表示在编译中可用,运行就没用了。
RUNTIME表示运行时可用。
这三种的区别解释起来很麻烦,总之一搬我们都是使用RUNTIME

(2)@Target 用来描述作用域,Target有目标的意思,你这个注解要给哪个目标修饰,这个属性可以选以下的值
CONSTRUCTOR用于描述构造器
FIELD用于描述域
LOCAL_VARIABLE用于描述局部变量
METHOD用于描述方法
PACKAGE用于描述包
PARAMETER用于描述参数
这个就是说,你允许把注解写在什么地方。这个属性是可以多选的,比如@Target({ElementType.FIELD, ElementType.METHOD})

(3)@Inherited 描述是否可以为继承,默认是false

(4)@Documented 描述是否会保存到 Javadoc 文档中

一般我们只会用到前面两个,所以后面两个我就不解释了。

3.注解的值

可以给注解设置值,比如说我上面的代码,就在注解里写了个

int value() default -1;

表示在使用注解时需要传一个整形的值

@BindView(R.id.tv)
TextView textView;

我这传了个R.id.tv就是一个整形的值。只有一个值的时候,必须以** value()**来命名,然后调用时就直接传就行。我还是分情况来说吧。

(1)不需要传值的情况

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface BindView {

}

调用

@BindView
TextView textView;

(2)传一个值的情况
就是我上面写的代码

(3)传多个值的情况

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface BindView {
    int age;
    String name;
}

调用

@BindView(age = 18, name = "JackMa")
TextView textView;

最后,这个default 表示设置默认值的意思。

三.调用注解

上面我们创建出了注解并定义好,然后我们需要调用这个注解,那怎么调用呢,一般我们调用一个类或接口都是new 出来,但是这东西怎么看都觉得new不出来吧,所以我们需要用反射来获取到注解的对象,然后进行调用

我不想去讲反射的内容,不然就没完了。就说个思路,需要用到哪个方法可以去查api。
注解在Java中就是Annotation懂吧,所以在反射中和Annotation相关的方法都是和注解相关的方法。

比如说获取注解,我就可以调用.getAnnotation(BindView.class)
再比如说我判断注解存在不,可以调用isAnnotationPresent()
总之你只要记住注解是Annotation,之后你不管是在反射中还是在哪里找和注解相关的方法,都先往Annotation这个名词相关的地方找准没错。

如果你不懂反射这里说再多也没有。

四.案例

其实说了这么多,到底哪里需要使用到注解呢,如果不使用到,讲它有啥用,我个人是目前接触到AOP涉及注解比较频繁,其它时候,比如说ButterKnife,Dagger,Retrofit等等这些主流的框架都会用到注解,包括java后台,我接触过spring会涉及到IOC啊AOP啊这些思想用java来实现也是用到注解比较多,所以可以来写个小demo试试。

不如就仿照ButterKnife吧,我之前没看过ButterKnife的源码啊,我就按照我学会的注解的知识和ButterKnife的调用方法来仿写个ButterKnife

1.首先定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface BindView {
    int value() default -1;
}

定义注解,要求传个资源进来,默认是-1

2.按照ButterKnife的调用的样子来写调用的地方
public class MainActivity extends AppCompatActivity {

    @BindView(R.id.tv)
    TextView textView;
    @BindView(R.id.btn)
    Button btn;

    String yyy = "aasdasdas";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        textView.setText("wwwwwwwwwwwwww");
        btn.setText("btn");
    }
}

发现ButterKnife调用的地方使用这 ButterKnife.bind(this); 那我就推测findViewById就在这个ButterKnife类的bind方法中进行。

3.定义ButterKnife
public class ButterKnife {

    public static void bind(Activity activity){
        Class<?> cls = activity.getClass();
        Field[] fields = cls.getDeclaredFields();
        for (Field field : fields) {
            BindView bindView = field.getAnnotation(BindView.class);
            if (bindView != null) {
                int ids = bindView.value();
                try {
                    field.set(activity, activity.findViewById(ids));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

我这里就用了反射来操作,调用bind方法后,先用cls.getDeclaredFields();获取所有的全局变量,然后再对每个变量用field.getAnnotation(BindView.class);来获取这个变量上面的注解,如果存在的话 int ids = bindView.value(); 来获取我们传入的资源,最后调用findViewById

field.set(activity, activity.findViewById(ids));

很简单吧,三个类这样就能实现了ButterKnife的效果


img_5ac01d4d583815ddca92d8de2749129a.png
image.png

注意判空一定要写,即使你全部的变量都用了注解,但是如果你DeBug看看,你会发现,变量中不仅仅只有你定义的,还存在其他的。

其实上面都是瞎写的,ButterKnife的原理根本不是这样,虽然我没看过源码,但我听别人说过ButterKnife的实现并不是这样的,我这的demo只是仿照了这个功能,具体ButterKnife的原理以后如果有时间我会单独写。

通过上面的讲解就能简单的实现注解,我也顺便复习加总结了一遍。

目录
相关文章
|
21天前
|
Java API 调度
Android系统 自定义开机广播,禁止后台服务,运行手动安装应用接收开机广播
Android系统 自定义开机广播,禁止后台服务,运行手动安装应用接收开机广播
43 0
|
21天前
|
存储 Java Linux
Android Mstar增加IR 自定义遥控头码完整调试过程
Android Mstar增加IR 自定义遥控头码完整调试过程
29 1
|
1月前
|
缓存 测试技术 Android开发
深入探究Android中的自定义View绘制优化策略
【4月更文挑战第8天】 在Android开发实践中,自定义View的绘制性能至关重要,尤其是当涉及到复杂图形和动画时。本文将探讨几种提高自定义View绘制效率的策略,包括合理使用硬件加速、减少不必要的绘制区域以及利用缓存机制等。这些方法不仅能改善用户体验,还能提升应用的整体性能表现。通过实例分析和性能测试结果,我们将展示如何有效地实现这些优化措施,并为开发者提供实用的技术指南。
|
1月前
|
前端开发 Android开发 开发者
深入探究Android中的自定义View组件开发
【4月更文挑战第3天】 在现代Android应用程序的开发过程中,创建具有独特功能和高度定制化的用户界面是一个常见需求。为此,理解并掌握自定义View组件的开发成为了开发者必备的技能之一。本文将深入探讨如何在Android中创建自定义View,从基础的绘制原理到事件处理机制,再到性能优化技巧,旨在为读者提供一个全面的技术视角,并通过实例代码演示如何实现一个功能丰富、响应迅速的自定义View组件。
|
1月前
|
XML Java Android开发
Android实现自定义进度条(源码+解析)
Android实现自定义进度条(源码+解析)
59 1
|
5月前
|
XML Android开发 数据安全/隐私保护
Android 自定义开源库 EasyView
Android 自定义开源库 EasyView
|
2天前
|
存储 消息中间件 缓存
Android应用开发:实现自定义View的高效绘制
【5月更文挑战第12天】 在Android开发中,创建高性能的自定义视图是一项挑战,它要求开发者深入理解Android的绘图机制以及UI渲染过程。本文将探讨如何优化自定义View的绘制流程,减少不必要的重绘和布局计算,以提升应用的响应速度和流畅度。我们将介绍几种关键策略,包括利用硬件加速、缓存绘制内容和使用高效的数据结构来存储视图状态。通过实例分析和性能对比,读者将学会如何在自己的应用中运用这些技巧,从而打造出更加流畅和响应迅速的用户界面。
|
4天前
|
XML Android开发 数据格式
Android下自定义Button样式
Android下自定义Button样式
10 3
|
5天前
|
XML Java Android开发
如何美化android程序:自定义ListView背景
如何美化android程序:自定义ListView背景
|
5天前
|
搜索推荐 Android开发
自定义Android标题栏TitleBar布局
自定义Android标题栏TitleBar布局