Android AOP(AspectJ)编程入门

AOP,即面向切面编程。
定义:

把某一方面的一些功能提取出来与一批对象进行隔离,提取之后我们就可以对某个单方面的功能进行编程。

举个例子,app中许多功能都必须要求用户手机联网才能进行。写代码的时候,我们得加上判断:

if(能联网)
    balabala..
else
    提示用户检查手机网络

显然,这段逻辑需要重复写很多次,而aop的作用就是将你从不断的重复劳动中解放出来。
这里我们需要借助第三方的编译工具 AspectJ

下载aspectj 地址: http://www.eclipse.org/aspectj/downloads.php
选择一个版本下载完成后解压出里面的

Android AOP(AspectJ)编程入门_第1张图片
image.png

放到libs中并添加至项目依赖:
image.png

修改build.gradle:

apply plugin: 'com.android.application'
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.9'
        classpath 'org.aspectj:aspectjweaver:1.8.9'
    }
}

repositories {
    mavenCentral()
}

android {
    ...
}

final def log = project.logger
final def variants = project.android.applicationVariants

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;
            }
        }
    }
}

dependencies {
    ...
}

至此aspectJ配置完成。

下面介绍AspectJ如何处理切面,以判断手机网络是否连通为例:

1、自定义一个注解,作用目标为方法。被注解的方法即为切点。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckNet {

}

2、处理切面逻辑

@Aspect
public class CheckNetAspect {

    /**
     *  找到处理切点,即切点注解
     *  * *代表所有方法,(..)代表所有参数,这里可以根据具体的方法类型来做处理
     */
    @Pointcut("execution(@com.android.pronetway.SchoolGoods.ioc.CheckNet * *(..))")
    public void insertBehvior() {

    }

    /**
     * 如何处理切面
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("insertBehvior()")
    public Object dealPont(ProceedingJoinPoint joinPoint) throws Throwable {
        final MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        final CheckNet checkNet = signature.getMethod().getAnnotation(CheckNet.class);
        if (checkNet != null) {
            final boolean connected = NetworkUtils.isConnected();
            if (!connected) {
                ToastUtils.showShort("请检查您的网络");
                return null;
            }
        }
        return joinPoint.proceed();
    }
}

3、使用很简单,如获取短信验证码的方法,直接在上面加上@CheckNet注解,即可在发送请求前先判断手机网络。如果没网,会提示"请检查您的网络",而不走方法内逻辑。:

@CheckNet
public void getCheckCode(String number) {
    //doSomething...
}

4、反编译看下里面的魔法
该框架在编译时自动生成相关代码,并不会有效率上的问题,我们可以反编译看下.class文件:

  private static final Object getCheckcode_aroundBody1$advice(LoginPresenter paramLoginPresenter, String paramString, JoinPoint paramJoinPoint, CheckNetAspect paramCheckNetAspect, ProceedingJoinPoint paramProceedingJoinPoint)
  {
    if (((CheckNet)((MethodSignature)paramProceedingJoinPoint.getSignature()).getMethod().getAnnotation(CheckNet.class) != null) && (!NetworkUtils.isConnected()))
    {
      ToastUtils.showShort("请检查您的网络");
      return null;
    }
    getCheckcode_aroundBody0(paramLoginPresenter, paramString, paramProceedingJoinPoint);
    return null;
  }

  private static final void getCheckcode_aroundBody0(LoginPresenter paramLoginPresenter, String paramString, JoinPoint paramJoinPoint)
  {
    //doSomething...
  }

  @CheckNet
  public void getCheckcode(String paramString)
  {
    JoinPoint localJoinPoint = Factory.makeJP(ajc$tjp_0, this, this, paramString);
    getCheckcode_aroundBody1$advice(this, paramString, localJoinPoint, CheckNetAspect.aspectOf(), (ProceedingJoinPoint)localJoinPoint);
  }

你可能感兴趣的:(Android AOP(AspectJ)编程入门)