今天的主题是 Annotation ,相信大家多多少少都有用过它。
在开始之前先简单的介绍一下自己。 注解能给我们带来很多好处.... 一般来说,注解有两种分类方式 @Target里面的ElementType是用来指定Annotation类型可以用在哪一些元素上的. 从RetentionPolicy的源码中看出,该枚举有三种类型。 APT是一个命令行工具,它对源代码文件进行检测找出其中的annotation后,使用annotation processors来处理annotation。 自定义一个Processor来编写编译时注解 Processor各个方法的作用 很多第三方库都使用了注解,简化了开发。比如说butterknife,简化了findViewById、setOnClickListener等等,让开发者摆脱一些繁琐的细节,更加关注于业务代码的开发。同时,我们项目中的一些通用组件也可以提取出来。如果能用注解封装的话,那就更加方便了。 自定义一个注解 MyAnnotation,只能作用于方法。 再写一个类AnnotationExample,在某个方法上标注@MyAnnotation 解析类AnnotationExample,通过反射获取testMethod(),并遍历该方法所使用的注解并打印出来。 如果testMethod()有@MyAnnotation的话,则打印key和value。 最终,可以看到打印出来的key和value的值 JavaPoet是我比较推荐的一个框架,它是由Square开发的。
这是一个JavaPoet生成一个HelloWorld类的例子,JavaPoet有一套自己的生成规则,大家对此感兴趣的话可以搜一下,也可以看一下我后面分享两个项目的源码,在这里我就不展开了。
下面两篇文章虽然是用Kotlin来实现编译时注解,但是思想是一样,Kotlin的语法不难理解。
在build文件夹下能找到编译时注解生成的文件,打开任意一个类,可以看到JavaPoet生成的代码。
一个aspectj的例子,具体用法稍后会提到。
这个类可能有点难理解,在AsyncAspect中用到了Rxjava2的Flowable,以后要是有机会的话跟大家可以给大家讲一下Rxjava2
另一个使用aspectj的例子。
在某个方法名前如果标注了@Cache,那就把该方法的返回结果放入缓存中,甚至还可以有缓存的过期时间。
简化版本的ButterKnife,这个库更加轻量级只做了几个最常用的注解,并且它是完全基于Kotlin进行开发的。
整个库包括三个模块: 1)injectview:android library,包括Injector类和ViewBinder接口。用于在Activity、Fragment、View、Dialog中进入注入。 2)injectview-annotations:java library,用于存放各个注解,比如@InjectView。 3)injectview-compiler:java library,使用apt来生成代码
页面路由框架,无论在android还是在iOS的开发中都是很常见的模块与模块之间的解耦工具,特别是对中大型App而言,基本上都会有自己的路由框架。
saf-router:是整个路由框架的核心,可以单独使用。 saf-router-annotation:是路由框架的注解模块,可以基于注解来声明router跳转的页面。 saf-router-compiler:由于我们的注解是编译时注解,而非运行时注解。在程序编译时会生成一个RouterManager的类,此类会管理App的router mapping信息。
我们sdk中提供了两个注解,简化开发者集成我们sdk的难度。这两个注解都是运行时的,虽然编译时注解效率更高,考虑到集成难度和尽量减少sdk的体积角度,最终还是使用运行时注解。
这是一个注解解析的类,将使用注解的Activity保持到一个map中。
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
如果说,面向过程的编程是一维的,那么面向对象的编程就是二维的。OOP从横向上区分出一个个的类,相比过程式增加了一个维度。而面向切面结合面向对象编程是三维的,相比单单的面向对象编程则又增加了“方面”的维度。
AOP是一种关注点分离的技术。我们软件开发时经常提一个词叫做“业务逻辑”或者“业务功能”,我们的代码主要就是实现某种特定的业务逻辑。但是我们往往不能专注于业务逻辑,比如我们写业务逻辑代码的同时,还要写事务管理、缓存、日志等等通用化的功能,而且每个业务功能都要和这些业务功能混在一起,非常非常地痛苦。为了将业务功能的关注点和通用化功能的关注点分离开来,就出现了AOP技术。 告别Thread、Handler、BroadCoast等方式更简单的执行异步方法。只需在目标方法上标注@Async 可以清晰地看到当前的线程和UI线程是不一样的。 基于Spring Cache风格的注解,在 initData() 上标注 @Cacheable 注解和缓存的key。将initData()返回的结果放入缓存中,缓存的key是address
在调试时,如果一眼无法看出错误在哪里,那肯定会把一些关键信息打印来。
目前,方法的入参和出参只支持基本类型和String,未来我会加上支持任意对象的打印以及优雅地展现出来。
通常,在 App 的开发过程中会在一些关键的点击事件、按钮、页面上进行埋点,方便数据分析师、产品经理在后台能够查看和分析。 以前在大的电商公司,每次 App 发版之前,都要跟数据分析师一起过一下看看哪些地方需要进行埋点。发版在即,添加代码会非常仓促,还需要安排人手进行测试。而且埋点的代码都很通用,所以产生了 @Hook 这个注解。它可以在调用某个方法之前、以及之后进行hook。可以单独使用也可以跟任何自定义注解配合使用。
先打印method1() is called before initData(),再打印initData(),最后打印method2() is called after initData()。
@Prefs 的用法跟之前的 @Cacheable 类似,区别是将结果放到SharedPreferences。
一般情况,写下这样的代码肯定会抛出空指针异常,从而导致App Crash。 使用 @Safe 可以确保即使遇到异常,也不会导致 App Crash,给 App 带来更好的用户体验。 再看一下logcat的日志,App 并没有 Crash 只是把错误的日志信息打印出来。
无论是开发 App 还是 Service 端,我们经常会用做一些性能方面的测试,比如查看某些方法的耗时。从而方便开发者能够做一些优化的工作。@Trace 就是为这个目的而产生的。
这个库包含了上面所有的注解操作,我自己开发app时也在用,而且新的使用方法我也会不断地更新。
在gradle中,如果apt插件跟aspectj插件一起使用,会报错。 在尝试了N个aspectj插件后,终于找到沪江的插件不错,解决了冲突问题。
最后,有问题可以在微信里询问我,也可以关注我的公众号,每周都会定期更新原创的技术文章。目前正在连载Scala学习笔记和Android上的图像框架。
关注【Java与Android技术栈】 更多精彩内容请关注: |
|
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|