Android 进阶篇之AOP
16lz
2021-01-23
AOP 大家应该都了解过一点,也就是我们所说的面向切面编程,与之相对应的还有 OOP 面向对象编程、POP 面向过程编程,下面我们就一起学习下在 Android 中 AOP 的环境配置以及怎么使用
环境配置
在项目根目录下的 build.gradle 配置
buildscript { repositories { jcenter() google() } dependencies { ... classpath 'org.aspectj:aspectjtools:1.9.2' classpath 'org.aspectj:aspectjweaver:1.9.2' }}
然后在 app module 目录下创建 aspectj.gradle,添加如下代码,代码中适配了常见的variant.javaCompile
编译警告
dependencies { implementation 'org.aspectj:aspectjrt:1.9.2'}import org.aspectj.bridge.IMessageimport org.aspectj.bridge.MessageHandlerimport org.aspectj.tools.ajc.Mainbuildscript { repositories { mavenCentral() } dependencies { classpath 'org.aspectj:aspectjtools:1.9.2' }}repositories { mavenCentral()}final def log = project.loggerfinal def variants = project.android.applicationVariantsvariants.all { variant -> if (!variant.buildType.isDebuggable()) { log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.") return } JavaCompile javaCompile = null if (variant.hasProperty('javaCompileProvider')) { TaskProvider provider = variant.javaCompileProvider javaCompile = provider.get() } else { javaCompile = variant.hasProperty('javaCompiler') ? variant.javaCompiler : variant.javaCompile } javaCompile.doLast { String[] args = ["-showWeaveInfo", "-1.8", "-inpath", javaCompile.destinationDir.toString(), "-aspectpath", javaCompile.classpath.asPath, "-d", javaCompile.destinationDir.toString(), "-classpath", javaCompile.classpath.asPath, "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)] log.debug "ajc args: " + Arrays.toString(args) MessageHandler handler = new MessageHandler(true); new Main().run(args, handler) for (IMessage message : handler.getMessages(null, true)) { switch (message.getKind()) { case IMessage.ABORT: case IMessage.ERROR: case IMessage.FAIL: log.error message.message, message.thrown break case IMessage.WARNING: log.warn message.message, message.thrown break case IMessage.INFO: log.info message.message, message.thrown break case IMessage.DEBUG: log.debug message.message, message.thrown break } } }}
最后在 app module 目录下 build.gradle 中引用
dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs')}apply from: "aspectj.gradle"
使用
在 Android 中常见的 AOP 使用有防止按钮多次点击
、检测登陆状态
,方法日志打印
等等,下面我们就来简单实现下防止按钮多次点击的功能
首先创建aop
包,在其包下分别创建annotation
和aspect
, 接着在annotation
包下创建SingleClick
注解
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface SingleClick {}
@Retention
有三个值可选
RetentionPolicy.SOURCE: 编译后会被丢弃。RetentionPolicy.CLASS: 编译后会被保留,但不会在运行的VM中保留。默认值RetentionPolicy.RUNTIME:编译后会被保留,也会在运行的VM中保留。
@Target
有如下值可选
ElementType.TYPE : 类型ElementType.FIELD: 字段,包括属性的支持字段。ElementType.METHOD: 方法ElementType.PARAMETER: 参数ElementType.CONSTRUCTOR: 构造函数ElementType.LOCAL_VARIABLE: 局部变量ElementType.ANNOTATION_TYPE: 注解类型ElementType.PACKAGE: 包名ElementType.TYPE_PARAMETER: 参数 java1.8开始ElementType.TYPE_USE: 使用的类型 java1.8开始
在aspect
包下创建SingleClickAspect
类,添加如下代码
@Aspectpublic class SingleClickAspect { private static int MIN_CLICK_DELAY_TIME = 600; private static long lastClickTime = 0L; //@Pointcut来标识所要寻找的切点,就是我们定义的@SingleClick注解 @Pointcut("execution(@com.soaic.helloaspect.aop.annotation.SingleClick * *(..))")//方法切入点 private void methodAnnotated() {} /** * joinPoint.proceed() 执行注解所标识的代码 * @After 可以在方法前插入代码 * @Before 可以在方法后插入代码 * @Around 可以在方法前后各插入代码 */ @Around("methodAnnotated()") private void aroundJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable{ //获取系统当前时间 long currentTime = Calendar.getInstance().getTimeInMillis(); //当前时间-上次记录时间>过滤的时间 过滤掉600毫秒内的连续点击 //表示该方法可以执行 if (currentTime - lastClickTime > MIN_CLICK_DELAY_TIME) { //将刚进入方法的时间赋值给上次点击时间 lastClickTime = currentTime; //执行原方法 joinPoint.proceed(); } }}
最后在按钮点击事件的方法里面声明@SingleClick
注解就可以了,使用起来是不是特别方便
@SingleClickprivate void login() {...}
在kotlin环境下配置
如果按照上面环境配置在 kotlin 里是不起作用的, 我们这里使用 github 开源的一个插件
GitHub地址: https://github.com/HujiangTechnology/gradle_plugin_android_aspectjx
使用如下:
同样是在项目根目录下的 build.gradle 配置
buildscript { ext.kotlin_version = '1.3.41' repositories { google() jcenter() } dependencies { ... classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.4' classpath 'org.aspectj:aspectjtools:1.9.2' }}
然后在 app module 下的 build.gradle 中配置
apply plugin: 'kotlin-android'apply plugin: 'kotlin-android-extensions'apply plugin: 'android-aspectjx'//或者这样也可以//apply plugin: 'com.hujiang.android-aspectjx'android { ... aspectjx { //排除所有package路径中包含`android.support`的class文件及库(jar文件) exclude 'android.support' }}dependencies {... implementation 'org.aspectj:aspectjrt:1.9.2'}
至此在 kotlin 下的环境配置就完成了。使用按照上面即可,感谢大家,我们下篇见~
更多相关文章
- Android系统默认Home应用程序(Launcher)的启动过程源代码分析(3)
- Android 注解指南
- Android建立对话框基本的几种方法
- 2种自定义android标题栏titleBar的方法
- Android通过chrome插件在线查看Android源代码
- 关于repo下载android代码时候错误的处理。
- Android Environment 的作用以及常用的方法