传统情况下,我们在Android中打印log都是通过类似于Log.d(TAG,"your log")这样的语句来进行log打印,但是你是否有时会觉得在你的代码逻辑中充斥着太多的log输出语句,想要改变一下呢?其实,我们可以使用AOP技术,来分离Android的log打印逻辑,减少逻辑代码中log打印语句的使用,更快速地打印Android log。
准备
首先,我们需要在项目中引入Aspectj,关于Android项目中添加Aspectj的支持,推荐github上的gradle_plugin_android_aspectjx项目,这是一个gradle插件,配置好之后即可启用Android上的AOP支持
开始
引入Aspectj的支持后,我们就可以进行Android下的AOP开发了,对于日志记录,我们先定义一个LogMethod注解
LogMethod.kt:
package com.example.aop.annotation
@Target(AnnotationTarget.FUNCTION) // 声明此注解的目标为函数
@Retention(AnnotationRetention.RUNTIME) // 由于添加了是否在函数执行前或函数执行后打印log的控制,所以这个注解需要在运行时仍然存在,用于在运行时获取注解参数的值
annotation class LogMethod(val before: Boolean = false, val after: Boolean = false) // 若before为true,则会在函数执行前打印log,若after为true,则会在函数执行后打印log,可同时设置为true
注解创建完成后,我们还需要定义一个切面来实现注解方法
LogMethodAspect.kt:
package com.example.aop
import android.util.Log
import com.example.aop.annotation.LogMethod
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Pointcut
import org.aspectj.lang.reflect.MethodSignature
import java.util.*
@Aspect // 声明这是一个切面以启用Aspectj
class LogMethodAspect {
// 定义切点为添加了该注解的函数
@Pointcut("execution(@com.example.aop.annotation.LogMethod * *(..))")
fun onLogMethod() {
}
// 因为需要在函数执行前后打印log,所以需要创建一个环绕通知
@Around("onLogMethod()&& @annotation(logMethod)")
@Throws(Throwable::class)
fun logMethod(joinPoint: ProceedingJoinPoint, logMethod: LogMethod): Any? {
val signature = joinPoint.signature as MethodSignature
// 在函数执行前打印log,并记录参数列表
if (logMethod.before) {
Log.d(signature.toShortString(), " Args : ${joinPoint.args?.let { Arrays.deepToString(joinPoint.args)}}")
}
// 执行函数
val result = joinPoint.proceed()
// 在函数执行后打印结果,并记录返回值,若无返回值,则打印void
if (logMethod.after) {
val type = signature.returnType.toString()
Log.d(signature.toShortString(), " Result : ${if ("void".equals(type, ignoreCase = true)) "void" else result}")
}
// 返回函数执行结果
return result
}
}
就这样,我们的注解就写好了,现在,只需要在需要记录log的函数前面加上@LogMethod(before = true, after = true)注解就行了,当然,可以根据需要,仅在函数执行前或执行后打印log
使用
我们可以创建一个MainActivity来测试我们编写的注解是否生效(部分无关代码已省略)
MainActivity.kt:
......
@LogMethod(before = true,after = true)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
@LogMethod(before = true)
override fun onStart() {
super.onStart()
}
@LogMethod(after = true)
override fun onStop() {
super.onStop()
}
......
运行此MainActivity,log的输出结果如下:
com.example.demo D/MainActivity.onCreate(..): Args : [null]
com.example.demo D/MainActivity.onCreate(..): Result : void
com.example.demo D/MainActivity.onStart(): Args : []
com.example.demo D/MainActivity.onStop(): Result : void
可以看到,我们并未在代码中使用任何log打印语句,即可成功监测函数的执行情况,达到了使用log进行代码执行情况跟踪的目的
总结
通过使用AOP技术,可以实现Android应用中log模块与应用业务逻辑分离的目的,减少了代码中log输出语句的目的,实现了log输出的集中管理,在实际使用中,还可以根据情况添加额外的判断(如自定义log的输出级别),增加了代码的可读性与可维护性。
但是由于受Android AOP实现的限制,目前在Android中仅支持基于注解的切入方式,这也意味着我们仅能针对类、属性或函数进行面向切面编程,所以本log记录注解只能针对函数使用,如果需要在代码块中输出log,仍需使用Android中的log打印函数来实现。
本文由 sung 创作,采用 知识共享署名4.0
国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Jun 4,2020