Android AOP框架AspectJ使用详解

 更新时间:2017年11月18日 09:03:42   作者:三十二蝉  
本篇文章主要介绍了Android AOP框架AspectJ使用详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

前言

之前了解过android的AOP框架,用法主要用来打日志;现在有一个需求需要函数在新线程中执行,并且函数主体执行完之后,在UI线程返回结果。想到手写的话,每次都要new Thread的操作,比较麻烦;因此就尝试用注解的方法解决这个问题。

AspectJ的使用核心就是它的编译器,它就做了一件事,将AspectJ的代码在编译期插入目标程序当中,运行时跟在其它地方没什么两样,因此要使用它最关键的就是使用它的编译器去编译代码ajc。ajc会构建目标程序与AspectJ代码的联系,在编译期将AspectJ代码插入被切出的PointCut中,已达到AOP的目的。

因此,无论在什么IDE上(如果使用命令行就可以直接使用ajc编译了),问题就是让IDE使用ajc作为编译器编译代码。

代码实现

注解使用

代码主要通过TraceLog、RunOnNewThread、RunOnNewThreadWithUICallback这三个注解与AOP容器关联。使用方法如下:

@TraceLog
@RunOnNewThread
public void checkAndRestartDownloadTask(final boolean isAutoCache) {
 DownloadManager.getInstance().startService(isAutoCache);
}


@TraceLog
@RunOnNewThreadWithUICallback
public Boolean isShowTipsForFirstVideoCache(DBQueryCallback<Boolean> callback) {
 if (!PreferenceClient.is_first_video_cache_done.getBoolean() &&
   (DownloadManager.getInstance().getFinishedTaskSize(true, false) > 0 ||
     DownloadManager.getInstance().getFinishedTaskSize(true, true) > 0)) {
  PreferenceClient.is_first_video_cache_done.setBoolean(true);
  return true;
 }
 return false;
}

checkAndRestartDownloadTask方法,希望方法体在一个新的线程执行并打印方法执行的Log;isShowTipsForFirstVideoCache方法,希望方法体在一个新的线程执行,并将函数的结果通过DBQueryCallback这个回调回传给UI线程,同时打印方法执行的Log。

AOP容器识别这三个注解,并实现注解解释器。

@Aspect
public class TudouDownloadAspect {
 public static final String TAG = TudouDownloadAspect.class.getSimpleName();

 private static final String THREAD_CALLBACK_POINT_METHOD =
   "execution(@com.download.common.aspect.RunOnNewThreadWithUICallback * *(.., com.download.common.callback.DBQueryCallback))";
 private static final String THREAD_CALLBACK_POINT_CONSTRUCTOR =
   "execution(@com.download.common.aspect.RunOnNewThreadWithUICallback *.new(.., com.download.common.callback.DBQueryCallback))";

 private static final String THREAD_POINT_METHOD =
   "execution(@com.download.common.aspect.RunOnNewThread * *(..))";
 private static final String THREAD_POINT_CONSTRUCTOR =
   "execution(@com.download.common.aspect.RunOnNewThread *.new(..))";

 private static final String LOG_POINT_METHOD =
   "execution(@com.download.common.aspect.TraceLog * *(..))";
 private static final String LOG_POINT_CONSTRUCTOR =
   "execution(@com.download.common.aspect.TraceLog *.new(..))";


 @Pointcut(THREAD_CALLBACK_POINT_METHOD)
 public void methodAnnotatedWithThread(){}
 @Pointcut(THREAD_CALLBACK_POINT_CONSTRUCTOR)
 public void constructorAnnotatedWithThread(){}

 @Pointcut(THREAD_POINT_METHOD)
 public void methodAnnotatedWithNewThread(){}
 @Pointcut(THREAD_POINT_CONSTRUCTOR)
 public void constructorAnnotatedWithNewThread(){}

 @Pointcut(LOG_POINT_METHOD)
 public void methodAnnotatedWithLog(){}
 @Pointcut(LOG_POINT_CONSTRUCTOR)
 public void constructorAnnotatedWithLog(){}

 /**
  * @RunOnNewThreadWithUICallback 的注解解释器
  * */
 @Around("methodAnnotatedWithThread() || constructorAnnotatedWithThread()")
 public Object wrapNewThreadWithCallback(final ProceedingJoinPoint joinPoint) throws Throwable {
  Log.v(TAG, "in wrapNewThreadWithCallback");
  Object[] objs = joinPoint.getArgs();
  final DBQueryCallback callback = (DBQueryCallback) objs[objs.length-1];
  new Thread(new Runnable() {
   @Override
   public void run() {
    try {
     final Object obj = joinPoint.proceed();
     DownloadClient.getInstance().mainHandler.post(new Runnable() {
      @Override
      public void run() {
       if (obj != null)
        callback.querySuccess(obj);
       else
        callback.queryFail();
      }
     });
    } catch (Throwable throwable) {
     throwable.printStackTrace();
    }
   }
  }).start();
  return null;
 }

 /**
  * @RunOnNewThread 的注解解释器
  * */
 @Around("methodAnnotatedWithNewThread() || constructorAnnotatedWithNewThread()")
 public void wrapNewThread(final ProceedingJoinPoint joinPoint) throws Throwable {
  Log.v(TAG, "in wrapNewThread");
  new Thread(new Runnable() {
   @Override
   public void run() {
    try {
     joinPoint.proceed();
    } catch (Throwable throwable) {
     throwable.printStackTrace();
    }
   }
  }).start();

 }

 /**
  * @TraceLog 的注解解释器
  * */
 @Before("methodAnnotatedWithLog() || constructorAnnotatedWithLog()")
 public void wrapWithLog(JoinPoint joinPoint) throws Throwable {
  Log.v(TAG, "before->" + joinPoint.getTarget().toString() + "---" + joinPoint.getSignature().getName());
 }

}

  1. @Aspect:声明一个AOP容器
  2. @Pointcut:声明一个切入点
  3. @Around:将函数主体包裹起来,在函数主体前、后插入代码
  4. @Before:在函数主体执行之前插入代码

使用Gradle脚本加载AOP容器

buildscript {
  repositories {
    mavenLocal()
    maven { url "https://jitpack.io" }
  }
  dependencies {
    classpath 'org.aspectj:aspectjtools:1.8.+' //AspectJ脚本依赖
  }
}

 dependencies {
    compile 'org.aspectj:aspectjrt:1.8.+' //AspectJ 代码依赖
  }

//AspectJ AOP容器加载脚本
final def log = project.logger
final def variants = project.android.libraryVariants
variants.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", 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;
      }
    }
  }
}

备注

@RunOnNewThreadWithUICallback这个注解的匹配规则需要函数的最后一个参数为DBQueryCallback(必须要有一个回调参数,不然怎么回传给UI线程~)。函数的返回值必须和DBQueryCallback的泛型类型一致,因为需要将返回值传入回调当中;

new Thread(new Runnable() {
   @Override
   public void run() {
    try {
     final Object obj = joinPoint.proceed();
     DownloadClient.getInstance().mainHandler.post(new Runnable() {
      @Override
      public void run() {
       if (obj != null)
        callback.querySuccess(obj);
       else
        callback.queryFail();
      }
     });
    } catch (Throwable throwable) {
     throwable.printStackTrace();
    }
   }
  }).start();

注意final Object obj = joinPoint.proceed();,执行了函数体以后,我们默认取到的是一个Object类型的返回值,所以不能用基本数据类型(bool用Boolean,int用Interger)。还有一点,Java中的null是可以转化为任意类型的,所以就算在函数体直接返回null,执行final Object obj = joinPoint.proceed();,这个类型转化也是不会有问题。亲测有效,可以放心使用

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Android AsyncTask使用以及源码解析

    Android AsyncTask使用以及源码解析

    这篇文章主要为大家详细解析了Android AsyncTask使用以及源码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-01-01
  • Android识别预装的第三方App方法实例

    Android识别预装的第三方App方法实例

    这篇文章主要给大家介绍了关于Android如何识别预装的第三方App的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧
    2019-01-01
  • Android实现短信发送功能

    Android实现短信发送功能

    这篇文章主要介绍了Android实现短信发送功能,对Android实现短信发送的每一步都进行了详细的介绍,感兴趣的小伙伴们可以参考一下
    2015-12-12
  • Android View进行手势识别详解

    Android View进行手势识别详解

    本文主要介绍 Android View进行手势识别,这里整理了相关资料和简单示例,有兴趣的小伙伴可以参考下
    2016-08-08
  • android自定义组件实现方法

    android自定义组件实现方法

    这篇文章主要介绍了android自定义组件实现方法,实例分析了Android实现自定义组件中页面布局及功能实现的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-07-07
  • Android中的序列化浅析

    Android中的序列化浅析

    这篇文章主要介绍了Android中的序列化浅析,本文讲解了序列化原因、序列化方法和代码实现等内容,需要的朋友可以参考下
    2015-03-03
  • Kotlin 协程 supervisorScope {} 运行崩溃解决方法

    Kotlin 协程 supervisorScope {} 运行崩溃解决方法

    看过很多 supervisorScope {} 文档的使用,我照抄一摸一样的代码,运行就崩溃,最后找到了解决方法,应该是kotlin版本更新做过改动,当前我使用的是 androidx.core:core-ktx:1.9.0,本文给大家介绍Kotlin 协程 supervisorScope {} 运行崩溃解决方法,感兴趣的朋友一起看看吧
    2024-01-01
  • android开发实现列表控件滚动位置精确保存和恢复的方法(推荐)

    android开发实现列表控件滚动位置精确保存和恢复的方法(推荐)

    下面小编就为大家带来一篇android开发实现列表控件滚动位置精确保存和恢复的方法(推荐)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-03-03
  • 浅析Android录屏 MediaRecorder

    浅析Android录屏 MediaRecorder

    MediaRecorder类是Android sdk提供的一个专门用于音视频录制,一般利用手机麦克风采集音频,摄像头采集图片信息。这篇文章主要介绍了Android录屏 MediaRecorder介绍,需要的朋友可以参考下
    2020-03-03
  • fragment实现隐藏及界面切换效果

    fragment实现隐藏及界面切换效果

    这篇文章主要为大家详细介绍了fragment实现隐藏及界面切换效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-11-11

最新评论