最近在回顾注解和反射方面的知识。

之前在项目开发过程中,也曾经体验过ButterKnife的注解,想结合反射和注解自己写一个框架。结合着大牛的博客,和自己的理解。实现了Activity加载layout和view初始化的注解。

一.原理

使用注解实现这样的功能,原理是什么呢?
反射+自定义annotation
首先自定义一个annotation
1.用于初始化View的自定义Annotation
package csu.lzw.reviewandroid.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** Created by Allen_Binan on 2016/4/2.*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LBindView {int id() default -1;
}

@Target用来表示这个注解修饰的对象是什么,FIELD表示是成员变量,例如Actvity当中的View控件。

@Retentiong表示这个注解是在什么级别保存信息。RUNTIME表示是运行时。

@interface是用于自定义注解的,它里面定义的方法的声明不能有参数,也不能抛出异常,并且方法的返回值被限制为简单类型、String、Class、emnus、@interface,和这些类型的数组。

注解@Target也是用来修饰注解的元注解,它有一个属性ElementType也是枚举类型,值为:ANNOTATION_TYPE,CONSTRUCTOR ,FIELD,LOCAL_VARIABLE,METHOD,PACKAGE,PARAMETER和TYPE,如@Target(ElementType.METHOD) 修饰的注解表示该注解只能用来修饰在方法上。

@RetentionRetention注解表示需要在什么级别保存该注释信息,用于描述注解的生命周期,它有一个RetentionPolicy类型的value,是一个枚举类型,它有以下的几个值:

1.用@Retention(RetentionPolicy.SOURCE)修饰的注解,指定注解只保留在源文件当中,编译成类文件后就把注解去掉;
     2.用@Retention(RetentionPolicy.CLASS)修饰的注解,指定注解只保留在源文件和编译后的class 文件中,当jvm加载类时就把注解去掉;
     3.用@Retention(RetentionPolicy.RUNTIME )修饰的注解,指定注解可以保留在jvm中,这样就可以使用反射获取信息了。

默认是RUNTIME,这样我们才能在运行的时候通过反射获取并做对应的逻辑处理。

同理可得,用于修饰Activity类,而加载layout布局的注解。

package csu.lzw.reviewandroid.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** Created by Allen_Binan on 2016/4/2.*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface LBindContentView {int layoutId() default -1;
}

最终,在Activity中实现的效果如下

package csu.lzw.reviewandroid;import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.Button;import csu.lzw.reviewandroid.annotation.LBindContentView;
import csu.lzw.reviewandroid.annotation.LBindView;
import csu.lzw.reviewandroid.annotation.LViewBindUtils;@LBindContentView(layoutId = R.layout.activity_main)
public class MainActivity extends AppCompatActivity {private static final String TAG="MainActivity";@LBindView(id=R.id.toggleButton)private Button tg;@LBindView(id = R.id.toggleButton2)private Button tg2;@LBindView(id = R.id.toggleButton3)private Button tg3;@LBindView(id = R.id.toggleButton4)private Button tg4;@LBindView(id = R.id.toggleButton5)private Button tg5;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);LViewBindUtils.inject(this);tg.setText("test");tg2.setText("test2");}}

关键的实现在于这一步

LViewBindUtils.inject(this);

这一步里做了什么呢

对于初始化view的注解,那么获取this指向的Activity中的成员,检查成员中是否有自定义的注解,如果有的话,获取注解中声明的id,使用反射,获取Activity的findviewbyid方法,使用invode调用,并将返回值通过反射赋值给将要初始化的view.

对于加载Activity布局的view,类似地,检查activity类上有没有自定义的注解,如果有的话,通过反射,调用setcontentview.

package csu.lzw.reviewandroid.annotation;import java.lang.reflect.Field;
import java.lang.reflect.Method;import android.app.Activity;
import android.util.Log;public class LViewBindUtils
{private static final String METHOD_SET_CONTENTVIEW = "setContentView";private static final String METHOD_FIND_VIEW_BY_ID = "findViewById";public static void inject(Activity activity){injectContentView(activity);injectViews(activity);// injectEvents(activity);}/*** 注入所有的view控件* * @param activity*/private static void injectViews(Activity activity){Class<? extends Activity> clazz = activity.getClass();Field[] fields = clazz.getDeclaredFields();// 遍历所有成员变量for (Field field : fields){LBindView viewInjectAnnotation = field.getAnnotation(LBindView.class);if (viewInjectAnnotation != null){int viewId = viewInjectAnnotation.id();if (viewId != -1){// 初始化Viewtry{Method method = clazz.getMethod(METHOD_FIND_VIEW_BY_ID,int.class);Object resView = method.invoke(activity, viewId);field.setAccessible(true);field.set(activity, resView);} catch (Exception e){e.printStackTrace();}}}}}/*** 注入主布局文件* * @param activity*/private static void injectContentView(Activity activity){Class<? extends Activity> clazz = activity.getClass();// 查询类上是否存在ContentView注解LBindContentView contentView = clazz.getAnnotation(LBindContentView.class);if (contentView != null)// 存在{int contentViewLayoutId = contentView.layoutId();try{Method method = clazz.getMethod(METHOD_SET_CONTENTVIEW,int.class);method.setAccessible(true);method.invoke(activity, contentViewLayoutId);} catch (Exception e){e.printStackTrace();}}}
}

Android开发 打造自己的Annotation框架相关推荐

  1. 移动周刊第 182 期:谈 Android 开发技巧、 iOS 系统框架实践

    写在前面 移动周刊第 182 期如约而至.如果你有好的文章以及优化建议,请发送邮件至mobilehub@csdn.net,在技术探索的道路上我们共同进步. YouTube 推出 VR 视频和 360 ...

  2. Android开发使用的常见第三方框架汇总

    1.volley 项目地址 https://github.com/smanikandan14/Volley-demo  (1)  JSON,图像等的异步下载:  (2)  网络请求的排序(schedu ...

  3. Android开发中用到的第三方框架汇总

    最近上网搜索了一些框架资料,整理了以下常用框架,希望在项目中有所帮助. 1.网络请求框架 android-async-http 该网络框架的介绍文章地址:http://www.cnblogs.com/ ...

  4. 云炬Android开发笔记 5-1,2网络框架接口创建

    1.网络框架接口创建 1.1 使用的是第三方的框架 [第三方框架]Retrofit,封装一个通用的框架,可以使用RxJava和RxAndroid进行封装,比较难,这里不做讲解: 1.2 restful ...

  5. Android 开发的两种框架 MVC和MVP 的简单分析

    在常见的android开发框架,有MVC和MVP两种,下面我来分别简单介绍一下. 一.MVC框架 MVC,即model(模型),view(视图),controler(控制器)三个单词的简称. 其中Mo ...

  6. Android开发指南中文版

    Android开发指南中文版 -应用程序框架   iefreer@hotmail.com 2009/9/10 个人主页: http://blog.csdn.net/iefreer 本文是对Androi ...

  7. Android开发软件架构思考以及经验总结

    欢迎关注我的知乎:井方哥 前言 架构设计,到底是什么呢?基于这段时间的学习和自己的一些思考,我认为架构是基于产品和技术所达成的一种共识.我不是专业的架构师,也不是经验老道的开发者.本文目的有三,一是整 ...

  8. Android 开发软件架构思考以及经验总结

    原文地址:http://blog.csdn.net/jf_1994/article/details/53870534 前言 架构设计,到底是什么呢?基于这段时间的学习和自己的一些思考,我认为架构是基于 ...

  9. Android开发-小技巧汇总2

    启动虚拟机时,在 launch options 窗口中 有个 wipe user data ,勾选它,将会让虚拟机 [恢复出厂设置] 2.[如果想让自己的应用程序有多个启动图标:] 为一个应用的 多个 ...

最新文章

  1. mysql基于replication实现最简单的M-S主从复制
  2. windows 7 旗舰版下无法安装 msi 文件 解决办法
  3. linux tail 命令,Linux tail命令的巧妙应用
  4. hotspot 默认 gc_默认HotSpot最大直接内存大小
  5. python 链表倒数第k个节点_链表-删除单链表中倒数第k个节点
  6. python云计算开发技术_云计算开发学习笔记:Python3 面向对象技术简介
  7. 关闭被占用的tomcat端口
  8. 群辉发布RackStation系列机型——RS3621RPxs、RS3621xs+与RS4021xs+
  9. 如果你被这个视频深深地震撼!那你一定是幸运的!
  10. Boost Asio Examples(整理)
  11. 【轨迹跟踪】基于matlab无人机轨迹跟踪【含Matlab源码 1152期】
  12. 在知乎上学 Python - 入门篇
  13. 全国计算机技术与软件专业技术资格(水平)考试2019年上半年考试公告(湖北省)
  14. [EULAR文摘] 超声滑膜炎和腱鞘炎对已获临床缓解患者病情复发的预测
  15. 阿里巴巴集团--软件测试--《社招、校招jd、公司具体介绍,校园招聘公告,应届生招聘流程,技术培训,薪资福利》整理
  16. CentOS下安装MRTG
  17. Java实战小游戏《flapper Bird》完整版,含源码
  18. 【vulnhub】Raven2
  19. 原型图、交互设计、UI图,到底啥关系
  20. 土地利用现状分析(城市三维,建筑等级现状)

热门文章

  1. 分析:公众号运营+引流,怎么从0到1运营
  2. 短视频剪辑如何才能更吸引人?
  3. 你应该了解的工厂方法模式:优雅的代码永不过时
  4. Unity Shader 学习笔记(33) 全局光照(GI)、反射探针、线性空间和伽马空间、高动态范围(HDR)
  5. Excel学习笔记:P10-图表制作(下)
  6. Java练习ArrayList的运用——勇者斗史莱姆
  7. 单词 of 《cyberspace :if you don't love it ,leave it 》
  8. 小米路由硬盘版搭建ftp服务和博客
  9. 面向对象程序设计中对抽象的理解
  10. 如何将数据存入mysql_怎样将数据存入mysql数据库