| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 移动开发 -> Android 注解原理学习及自定义注解 -> 正文阅读 |
|
[移动开发]Android 注解原理学习及自定义注解 |
书山有路勤为径,学海无涯苦做舟,苦海无涯,回头是岸 android注解,是JDK5.0引入的一种注解机制,主要是用于减少一些繁琐的工作,比如:findViewById...。现在有许多框架帮我们实现了相关的注解,方便且实用。但闲暇之余还是可以了解一下其中的原理,知其然也知其所以然。 下面我们就以简单的例子,来简单的学习一下android注解: 一、android 注解介绍:1.1、注解解释:JDK5.0内置了3个标准注解,4个元注解 @Override:检查方法是否是重写方法 @Desprecated:标记元素被废弃,使用该注解的元素,编译器会发出警告。 @SuppressWarnings:指示编译器忽略警告信息。 @Target:标记注解可用在什么地方(元注解) @Retention:标记注解可用在什么地方(元注解) @Documented:标记注解是否出现在 Javadoc 中(元注解) @Inherited:标记标注的Annotation是否具有继承性(元注解) 在JDK7.0之后,额外增加了3个注解: @SafeVarargs:忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告 @FunctionalInterface:标识一个匿名函数或函数式接口 @Repeatable:标识某注解可以在同一个声明上使用多次 注解有多个,详细的这儿不做过多介绍,自定义注解时,主要用到@Target和@Retention两个元注解,下面介绍一下这两个注解 1.2、@Target使用介绍@Target:标记用于什么地方,接收参数为枚举ElementType中的元素,下面来看一下ElementType这个枚举:
通过ElementType这个枚举,我们可以看出,@Target可以用于类、属性、方法、参数、构造方法等等地方,参数可以设置多个,例如: @Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD}) 表示这个注解可用于属性、类、方法上面。 1.3、@Target使用介绍使用@Retention:标记注解的策略,接收参数为枚举RetentionPolicy中的元素,我们来看一下RetentionPolicy:
具体含义看代码注释,此处不再重复解释 二、自定义注解:?2.1、定义注解定义注解时,需要使用到@interface关键字,类似下面的定义; @Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Myannotation { int viewId() default 0; int layoutId() default 0; int onclick() default 0; } ?此处定义了一个可用于属性、类方法的注解,注解接收三个int类型的参数,但都有默认值,默认值为0 ,所以使用的时候可以只传入其中的一部分。 2.2、使用注解2.1中定义的注解名称为Myannotation,使用注解的方式为在需要注解的属性、方法、类前面使用@Myannotation(参数)进行使用,例如以下代码: @Myannotation(layoutId = R.layout.activity_main)//注解类 public class MainActivity extends AppCompatActivity { private TXCloudVideoView mVideoViewAnchor; @Myannotation(viewId = R.id.button_1)//注解属性 private Button button1; @Myannotation(onclick = R.id.button_1)//注解方法 public void clickButton(View v){ Log.d("test", "被点击到了"); } } 2.3、注解如何生效??注解不能凭空生效,需要我们去对他进行解释处理,例如以下代码: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); AnnotionUtils.injectActivity(this);//处理注解 // TestAsyncTask task = new TestAsyncTask(); Integer[] years = new Integer[3]; button1.setText("click me,click me"); } ?利用 AnnotionUtils.injectActivity(this);这句代码对注解进行处理 接下来,我们从injectActivity(Activity activity)这个方法开始,看一下整个的处理流程: public static void injectActivity(Activity activity){ if(activity.getClass().isAnnotationPresent(Myannotation.class)){ Myannotation myannotation = activity.getClass().getAnnotation(Myannotation.class); activity.setContentView(myannotation.layoutId()); injectClick(activity);//处理点击方法 injectView(activity);//处理属性 } } ?代码比较简单,主要的流程是通过isAnnotationPresent这个方法,判断指定类型的注释是否存在于此元素上,如果存在,则返回TRUE。,然后通过getAnnotation(Class<A> annotationClass)方法,去获取到对应的注解对象,通过activity的setContentView绑定对应的布局文件layoutId. 接下来,我们再来看一下处理点击的方法,代码如下: public static void injectClick(Activity activity){ Class<?> activityClass = activity.getClass(); Method[] methods = activityClass.getMethods();//获取方法 for (int i = 0;i < methods.length;i++) { if (methods[i].isAnnotationPresent(Myannotation.class)){ Myannotation myannotation = methods[i].getAnnotation(Myannotation.class); Log.d("test", " | " + myannotation.onclick()); int finalI = i; activity.findViewById(myannotation.onclick()).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { methods[finalI].invoke(activity,v); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }); } } } ?首先通过activityClass.getMethods()方法获取到class中所有的方法(注:此处涉及到反射的知识点,我们下期一起学习一下反射) 然后遍历所有的方法,通过isAnnotationPresent方法判断,方法中是否含有Myannotation注解,如果含有,则做以下两步操作: 1、对传入的控件id,设置OnClickListener监听器 2、在onclick方法中调用被注解的方法。这儿要使用到反射中的invoke方法,先在此处简单的介绍一下这个方法,方法生命如下: 第一个参数,是调用此方法的对象,比如我们此处是要调用activity中的clickButton方法,所以第一个参数传入activity对象,Object... args是一个可变参数,clickButton接收哪些参数,此处就传入哪些参数。 methods[finalI].invoke(activity,v);在示例中,这样就达到了在点击id为button_1的button时,调用了activity中的clickButton方法。 最后我们来看一下处理属性的方法,代码如下: 这儿流程比较简单,也涉及到了反射的相关知识,简单来说分为两步: 1、 调用activityClass.getDeclaredFields()获取所有属性 2、通过isAnnotationPresent判断属性是否含有Myannotation,如果有,调用属性的set方法对属性进行赋值。 这里流程比较简单,但有两处需要注意(注释中也说明了): 1、获取属性,注意getDeclaredFields和getFields的区别,getFields只能获取到public的属性 2、获取到的私有属性赋值前,一定不能忘记设置setAccessible为true,否则不能修改成功 完整代码这边如下: Myannotation: @Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Myannotation { int viewId() default 0; int layoutId() default 0; int onclick() default 0; } ?MainActivity: @Myannotation(layoutId = R.layout.activity_main) public class MainActivity extends AppCompatActivity { private TXCloudVideoView mVideoViewAnchor; @Myannotation(viewId = R.id.button_1) private Button button1; @Myannotation(onclick = R.id.button_1) public void clickButton(View v){ Log.d("test", "被点击到了"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); AnnotionUtils.injectActivity(this);//处理注解 Integer[] years = new Integer[3]; button1.setText("click me,click me"); } } AnnotionUtils: public class AnnotionUtils { public static void injectActivity(Activity activity){ if(activity.getClass().isAnnotationPresent(Myannotation.class)){ Myannotation myannotation = activity.getClass().getAnnotation(Myannotation.class); activity.setContentView(myannotation.layoutId()); injectClick(activity);//处理点击方法 injectView(activity);//处理属性 } } public static void injectView(Activity activity){ Class<?> activityClass = activity.getClass(); Field[] fields = activityClass.getDeclaredFields();//获取属性,注意getDeclaredFields和getFields的区别,getFields只能获取到public的属性 for (int i = 0;i < fields.length;i++) { if (fields[i].isAnnotationPresent(Myannotation.class)){ try { Log.d("test", fields[i].getName() + " | " + fields[i].getAnnotation(Myannotation.class).viewId()); fields[i].setAccessible(true);//私有属性一定不能忘记设置access fields[i].set(activity,activity.findViewById(fields[i].getAnnotation(Myannotation.class).viewId())); } catch (IllegalAccessException e) { e.printStackTrace(); } } } } public static void injectClick(Activity activity){ Class<?> activityClass = activity.getClass(); Method[] methods = activityClass.getMethods();//获取方法 for (int i = 0;i < methods.length;i++) { if (methods[i].isAnnotationPresent(Myannotation.class)){ Myannotation myannotation = methods[i].getAnnotation(Myannotation.class); Log.d("test", " | " + myannotation.onclick()); int finalI = i; activity.findViewById(myannotation.onclick()).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { methods[finalI].invoke(activity,v); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }); } } } } ?xml布局文件: <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/button_1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <com.tencent.rtmp.ui.TXCloudVideoView android:id="@+id/video_view_anchor" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="visible" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> |
|
移动开发 最新文章 |
Vue3装载axios和element-ui |
android adb cmd |
【xcode】Xcode常用快捷键与技巧 |
Android开发中的线程池使用 |
Java 和 Android 的 Base64 |
Android 测试文字编码格式 |
微信小程序支付 |
安卓权限记录 |
知乎之自动养号 |
【Android Jetpack】DataStore |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/25 4:36:20- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |