Android 性能调优中,程使通常存在需要对方法的手进执行时间进行统计的需求,这样就可以看出哪些方法耗时多,阶性解是优h用详系统的瓶颈。最容易想到的全面P切方案是在每个方法的开头处获取系统时间,在方法的分析结尾处再次获取系统时间,前后两个时间戳的面编差值就是这个方法执行所消耗的总时间;
Hugo项目是一个调试函数调用耗时的工具,通过对方法或者类添加@DebugLog注解,程使在运行时会将函数的手进耗时打印在控制台中,通常用于排查函数耗时,或者用于卡顿检测;
hugo 这个框架麻雀虽小但五脏俱全,它使用了很多 Android 开发中流行的技术,例如注解,AOP,AspectJ,Gradle 插件;
hugo 以 gradle 插件的形式供开发者集成和使用,分为两步:
- buildscript {
- repositories {
- mavenCentral()
- }
- dependencies {
- classpath 'com.jakewharton.hugo:hugo-plugin:1.2.1' // 添加 Hugo 的 Gradle 插件依赖
- }
- }
- apply plugin: 'com.jakewharton.hugo' // 应用 Hugo 插件
①aspectjrt.jar:aspectJ 运行时的依赖库,想要使用 aspectJ 的功能都需要引入这个库;
hugo-annotations:hugo 的注解库,定义了 DebugLog 这个注解;
- @Target({ TYPE, METHOD, CONSTRUCTOR}) @Retention(CLASS)
- public @interface DebugLog {
- }
②hugo-runtime:hugo 的运行时库,是实现 hugo 日志功能的核心库;
③hugo-plugin:hugo 的插件库,主要实现了aop的插件;
- class HugoPlugin implements Plugin<Project> {
- @Override void apply(Project project) {
- def hasApp = project.plugins.withType(AppPlugin)
- def hasLib = project.plugins.withType(LibraryPlugin)
- if (!hasApp && !hasLib) {
- throw new IllegalStateException("'android' or 'android-library' plugin required.")
- }
- final def log = project.logger
- final def variants
- if (hasApp) {
- variants = project.android.applicationVariants
- } else {
- variants = project.android.libraryVariants
- }
- project.dependencies {
- debugCompile 'com.jakewharton.hugo:hugo-runtime:1.2.2-SNAPSHOT'
- // TODO this should come transitively
- debugCompile 'org.aspectj:aspectjrt:1.8.6'
- compile 'com.jakewharton.hugo:hugo-annotations:1.2.2-SNAPSHOT'
- }
- project.extensions.create('hugo', HugoExtension)
- variants.all { variant ->
- if (!variant.buildType.isDebuggable()) {
- log.debug("Skipping non-debuggable build type '${ variant.buildType.name}'.")
- return;
- } else if (!project.hugo.enabled) {
- log.debug("Hugo is not disabled.")
- return;
- }
- JavaCompile javaCompile = variant.javaCompile
- javaCompile.doLast {
- String[] args = [
- "-showWeaveInfo",
- "-1.5",
- "-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;
- }
- }
- }
- }
- }
- }
需要进行日志记录的类名或者方法名处使用 @DebugLog 注解标记即可;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- }
- @DebugLog
- private void test(String... tests) {
- for (String arg : tests) {
- Log.i("Args", arg);
- }
- }
AOP,全称为 Aspect Oriented Programming,即面向切面编程;AOP 是软件开发中的一个编程范式,通过预编译方式或者运行期动态代理等实现程序功能的统一维护的一种技术,它是 OOP(面向对象编程)的延续,利用 AOP 开发者可以实现对业务逻辑中的不同部分进行隔离,从而进一步降低耦合,提高程序的可复用性,进而提高开发的效率;
2.1、什么是AspectJ
①AspectJ实际上是对AOP编程思想的一个实践,AOP虽然是一种思想,但就好像OOP中的Java一样,一些先行者也开发了一套语言来支持AOP;
2.2、实现一个网络状态检测的AOP
①aspectj配置
项目的gradle中配置build.gradle(project)
- buildscript {
- repositories {
- google()
- mavenCentral()
- jcenter()
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:4.1.1'
- classpath 'org.aspectj:aspectjtools:1.8.6'
- }
- }
- ......
- ......
主app中build.gradle(app)
- dependencies {
- compile 'org.aspectj:aspectjrt:1.8.6'
- }
- android.libraryVariants.all { variant ->
- JavaCompile javaCompile = variant.javaCompile
- javaCompile.doLast {
- String[] args = [
- "-showWeaveInfo",
- "-1.5",
- "-inpath", javaCompile.destinationDir.toString(),
- "-aspectpath", javaCompile.classpath.asPath,
- "-d", javaCompile.destinationDir.toString(),
- "-classpath", javaCompile.classpath.asPath,
- "-bootclasspath", android.bootClasspath.join(File.pathSeparator)
- ]
- MessageHandler handler = new MessageHandler(true);
- new Main().run(args, handler)
- def log = project.logger
- 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:
- case IMessage.INFO:
- log.info message.message, message.thrown
- break;
- case IMessage.DEBUG:
- log.debug message.message, message.thrown
- break;
- }
- }
- }
- }
②aop实现
定义annotation:
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- public @interface CheckNetwork {
- }
代码注解:
- @CheckNetwork()
- private void checkNetwork() {
- LogUtil.i("AnnotationFragment", "检测完毕");
- }
关键处理切入点:
- @Aspect
- public class CheckNetworkAspect {
- private static final String TAG = CheckNetworkAspect.class.getSimpleName();
- /**
- * 找到处理的切点
- * * *(..) “**”表示是任意包名 “..”表示任意类型任意多个参数
- */
- @Pointcut("execution(@la.xiong.androidquick.demo.features.function.annotation.aspect.CheckNetwork * *(..))")
- public void executionCheckNetwork() {
- }
- /**
- * 处理切面
- *
- * @param joinPoint
- * @return
- */
- @Around("executionCheckNetwork()")
- public Object checkPermission(ProceedingJoinPoint joinPoint) throws Throwable {
- MethodSignature signature = (MethodSignature) joinPoint.getSignature();
- CheckNetwork annotation = signature.getMethod().getAnnotation(CheckNetwork.class);
- if (annotation != null) {
- Context context = AspectUtils.getContext(joinPoint.getThis());
- if (NetworkUtils.isConnected()) {
- Toast.makeText(context, "当前网络正常", Toast.LENGTH_SHORT).show();
- } else {
- Toast.makeText(context, "此时没有网络连接", Toast.LENGTH_SHORT).show();
- }
- return joinPoint.proceed();
- }
- return null;
- }
- }
AOP 能够实现将日志纪录,性能统计,埋点统计,安全控制,异常处理等代码从具体的业务逻辑代码中抽取出来,放到统一的地方进行处理;
利用 AOP 开发者可以实现对业务逻辑中的不同部分进行隔离,从而进一步降低耦合,提高程序的可复用性,进而提高开发的效率;
可以自定义属于你的功能比如:日志记录,性能统计,安全控制,事务处理,异常处理等等。
本文转载自微信公众号「Android开发编程」,可以通过以下二维码关注。转载本文请联系Android开发编程公众号。
责任编辑:姜华 来源: Android开发编程 AndroidAOPhugo
(责任编辑:休闲)
爱司凯(300521.SZ)2020年度净亏损1214.64万元 不以公积金转增股本
特朗普继续强硬执行民族主义保护政策 优衣库或选择退出美国市场
陕西省发展改革委刘迎军副主任赴镇巴开展对口帮扶工作 落实帮扶机制
格力分红方案总额超36亿元 除权除息日为2019年2月25日
中青旅(600138.SH):2020年度由盈转亏 基本每股亏损0.3206元