美文网首页
AspectJ在android上的开发

AspectJ在android上的开发

作者: JasonChen8888 | 来源:发表于2018-03-28 15:33 被阅读0次

    Android上运用AOP的思想开发,可以快速的帮助我们简化在横向开发中的重复性工作,简单的说就是把涉及到众多模块的某一类问题进行统一管理比如:性能检测、日志打印手机等。
    AspectJ实际上是对AOP编程思想的一个实践,当然,除了AspectJ以外,还有很多其它的AOP实现,例如ASMDex、javassist等,但目前最好、最方便的,依然是AspectJ。

    直接贴例子

    • 引入插件,这边是添加在app.gradle, 不是添加在项目的gradle中
    import org.aspectj.bridge.IMessage
    import org.aspectj.bridge.MessageHandler
    import org.aspectj.tools.ajc.Main
    
    buildscript {
      repositories {
        mavenCentral()
      }
      dependencies {
        classpath 'org.aspectj:aspectjtools:1.8.1'   //引入aspectj的classpath
      }
    }
    
    apply plugin: 'com.android.application'
    
    android {
      compileSdkVersion 26
      buildToolsVersion "26.0.2"
      defaultConfig {
        applicationId "m4399.aspectjdemo"
        minSdkVersion 19
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
      }
      buildTypes {
        release {
          minifyEnabled false
          proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
      }
    }
    
    dependencies {
      compile fileTree(dir: 'libs', include: ['*.jar'])
      compile 'com.android.support:appcompat-v7:26.+'
      compile 'com.android.support.constraint:constraint-layout:1.0.2'
      testCompile 'junit:junit:4.12'
      compile 'org.aspectj:aspectjrt:1.8.1'   //添加对应的依赖
    }
    
    
    final def log = project.logger
    final def variants = project.android.applicationVariants
    //在全局变量中配置编译项以及,对应的log输出
    variants.all { variant ->
      if (!variant.buildType.isDebuggable()) {
        log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
        return;
      }
    
      JavaCompile javaCompile = 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;
          }
        }
      }
    }
    
    • 编写注解
    @Retention(RetentionPolicy.CLASS)
    @Target({ ElementType.CONSTRUCTOR, ElementType.METHOD })
    public @interface DebugTrace {
    }
    
    • 日志打印类
    public class DebugLog {
      private DebugLog() {}
    
      /**
       * Send a debug log message
       *
       * @param tag Source of a log message.
       * @param message The message you would like logged.
       */
      public static void log(String tag, String message) {
        Log.d(tag, message);
      }
    }
    
    • 方法耗时检测类
    public class StopWatch {
    
      private long startTime;
      private long endTime;
      private long elapsedTime;
    
      public StopWatch() {
        //empty
      }
    
      private void reset() {
        startTime = 0;
        endTime = 0;
        elapsedTime = 0;
      }
    
      public void start() {
        reset();
        startTime = System.nanoTime();
      }
    
      public void stop() {
        if (startTime != 0) {
          endTime = System.nanoTime();
          elapsedTime = endTime - startTime;
        } else {
          reset();
        }
      }
    
      public long getTotalTimeMillis() {
        return (elapsedTime != 0) ? TimeUnit.NANOSECONDS.toMillis(endTime - startTime) : 0;
      }
    }
    
    • Aspect 类的开发
    @Aspect
    public class TraceAspect {
    
      private static final String POINTCUT_METHOD =
          "execution(@com.bao.aspectjdemo.DebugTrace * *(..))";  //对应着注解类的包名+类名
    
      private static final String POINTCUT_CONSTRUCTOR =
          "execution(@com.bao.aspectjdemo.DebugTrace *.new(..))";
    
      @Pointcut(POINTCUT_METHOD)
      public void methodAnnotatedWithDebugTrace() {}
    
      @Pointcut(POINTCUT_CONSTRUCTOR)
      public void constructorAnnotatedDebugTrace() {}
    
      @Around("methodAnnotatedWithDebugTrace() || constructorAnnotatedDebugTrace()")
      public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String className = methodSignature.getDeclaringType().getSimpleName();
        String methodName = methodSignature.getName();
    
        final StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        Object result = joinPoint.proceed();
        stopWatch.stop();
    
        DebugLog.log(className, buildLogMessage(methodName, stopWatch.getTotalTimeMillis()));
    
        return result;
      }
    
      /**
       * Create a log message.
       *
       * @param methodName A string with the method name.
       * @param methodDuration Duration of the method in milliseconds.
       * @return A string representing message.
       */
      private static String buildLogMessage(String methodName, long methodDuration) {
        StringBuilder message = new StringBuilder();
        message.append("AspectJDemo --> ");
        message.append(methodName);
        message.append(" --> ");
        message.append("[");
        message.append(methodDuration);
        message.append("ms");
        message.append("]");
    
        return message.toString();
      }
    }
    
    
    • 调用
      @DebugTrace
      @Override
      public void onClick(View v) {
        try {
          Thread.sleep(10);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    

    以上是个人参考例子https://github.com/android10/Android-AOPExample 熟悉了一遍
    补充:Android-AOPExample的例子下载下来,在gradle版本再2.3.0及其以上的版本编译会出现问题
    报错误:No such property: project for class: com.android.build.gradle.LibraryPlugin

    • 解决方法一:注释掉LibraryPlugin plugin = project.plugins.getPlugin(LibraryPlugin)
      和 "-bootclasspath", plugin.project.android.bootClasspath.join(File.pathSeparator)
    • 解决方法二:将plugin.project.android.bootClasspath.join(File.pathSeparator) 替换为 android.bootClasspath.join(File.pathSeparator)

    参考文章:

    相关文章

      网友评论

          本文标题:AspectJ在android上的开发

          本文链接:https://www.haomeiwen.com/subject/ojnycftx.html