AndroidStudio 配置 AspectJ 环境实现AOP的方法
昨天看了一段android配置aspectj实现AOP的直播视频,就试着自己配置了一下,可能是因为我自己的AndroidStudio环境的问题,碰到了不少的坑(其实还是因为对gradle理解的不多),但总归是配置好了,就分享一下。
试了两种方式,不过项目下的build.gradle,没什么变化,直接看一下代码吧:
build.gradle(项目下)
buildscript{ ext{ //androidappcompat支持库版本 androidSupportVersion='26.1.0' //编译的SDK版本,如API20 compileSdkVersion=26 //构建工具的版本,其中包括了打包工具aapt、dx等,如API20对应的build-tool的版本就是20.0.0 buildToolsVersion="26.0.2" //兼容的最低SDK版本 minSdkVersion=15 //向前兼容,保存新旧两种逻辑,并通过if-else方法来判断执行哪种逻辑 targetSdkVersion=26 //kotlin版本号 kotlin_version='1.2.10' kotlinVersion="org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" appcompatV7="com.android.support:appcompat-v7:$androidSupportVersion" appcompatDesign="com.android.support:design:$androidSupportVersion" constraintLayout='com.android.support.constraint:constraint-layout:1.0.2' } repositories{ google() jcenter() mavenCentral() } dependencies{ classpath'com.android.tools.build:gradle:3.0.1' classpath"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath'org.greenrobot:greendao-gradle-plugin:3.2.1' //NOTE:Donotplaceyourapplicationdependencieshere;theybelong //intheindividualmodulebuild.gradlefiles classpath'org.aspectj:aspectjtools:1.8.13' classpath'org.aspectj:aspectjweaver:1.8.13' } } allprojects{ repositories{ google() jcenter() mavenCentral() } } taskclean(type:Delete){ deleterootProject.buildDir }
看着一大堆,主要就是下面这几行配置,其他的是我自己项目中用到的,根据自己需要配置就行。
buildscript{ repositories{ mavenCentral() } dependencies{ classpath'org.aspectj:aspectjtools:1.8.13' classpath'org.aspectj:aspectjweaver:1.8.13' } } repositories{ mavenCentral() }
其实这几行配置在app的build.gradle里也是可以的,但是因为项目下的build.gradle里已经有buildscript{}、allprojects{repositories{}},就配置在这里了。
然后有两种配置方式:
第一种
只有一个主Moduleapp的情况下,配置app的build.gradle:
applyplugin:'com.android.application' applyplugin:'kotlin-android' applyplugin:'kotlin-android-extensions' applyplugin:'org.greenrobot.greendao' android{ compileSdkVersionrootProject.ext.compileSdkVersion buildToolsVersionrootProject.ext.buildToolsVersion defaultConfig{ applicationId"填入自己的applicationId" minSdkVersionrootProject.ext.minSdkVersion targetSdkVersionrootProject.ext.targetSdkVersion versionCode1 versionName"1.0" //Lambda配置 //jackOptions.enabled=true //android.compileOptions.sourceCompatibility1.8 buildConfigField"boolean","LOG","true"//显示Log testInstrumentationRunner"android.support.test.runner.AndroidJUnitRunner" //支持矢量图 vectorDrawables.useSupportLibrary=true ndk{ //选择要添加的对应cpu类型的.so库。 abiFilters'armeabi','armeabi-v7a','arm64-v8a','x86','x86_64','mips','mips64' } } buildTypes{ release{ minifyEnabledfalse buildConfigField"boolean","LOG","false"//显示Log proguardFilesgetDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro' } } //Lambda配置 compileOptions{ sourceCompatibilityJavaVersion.VERSION_1_8 targetCompatibilityJavaVersion.VERSION_1_8 } dataBinding{ enabledtrue } greendao{ schemaVersion1//数据库版本号 daoPackage'com.test.qby.newtestapplication.greendao'//设置DaoMaster、DaoSession、Dao包名 targetGenDir'src/main/java'//设置DaoMaster、DaoSession、Dao目录 //targetGenDirTest:设置生成单元测试目录 //generateTests:设置自动生成单元测试用例 } lintOptions{ abortOnErrortrue } } dependencies{ implementationfileTree(include:['*.jar'],dir:'libs') implementationrootProject.ext.kotlinVersion implementationrootProject.ext.appcompatV7 implementationrootProject.ext.constraintLayout compilerootProject.ext.appcompatDesign testImplementation'junit:junit:4.12' androidTestImplementation'com.android.support.test:runner:1.0.1' androidTestImplementation'com.android.support.test.espresso:espresso-core:3.0.1' compile'jp.wasabeef:glide-transformations:3.0.1' //IfyouwanttousetheGPUFilters compile'jp.co.cyberagent.android.gpuimage:gpuimage-library:1.4.1' //腾讯bugly compile'com.tencent.bugly:crashreport:latest.release' compile'com.tencent.bugly:nativecrashreport:latest.release' //retrofit compile'com.squareup.retrofit2:retrofit:2.3.0' compile'com.squareup.retrofit2:converter-gson:2.3.0' compile'com.squareup.retrofit2:adapter-rxjava2:2.3.0' compile'com.squareup.okhttp3:logging-interceptor:3.9.0' //rxJava compile'io.reactivex.rxjava2:rxandroid:2.0.1' //BecauseRxAndroidreleasesarefewandfarbetween,itisrecommendedyoualso //explicitlydependonRxJava'slatestversionforbugfixesandnewfeatures. compile'io.reactivex.rxjava2:rxjava:2.1.8' //greenDao compile'org.greenrobot:greendao:3.2.0' //换肤功能 compile'com.zhy:changeskin:4.0.2' //AOP面向切面编程,加入这行就不用在libs下引入jar包了,不然要写成compilefile(libs/aspectjrt.jar) compile'org.aspectj:aspectjrt:1.8.13' } /* //在项目下配置了,此处就不需要了 buildscript{ repositories{ mavenCentral() } dependencies{ classpath'org.aspectj:aspectjtools:1.8.13' classpath'org.aspectj:aspectjweaver:1.8.13' } } repositories{ mavenCentral() } */ importorg.aspectj.bridge.IMessage importorg.aspectj.bridge.MessageHandler importorg.aspectj.tools.ajc.Main finaldeflog=project.logger finaldefvariants=project.android.applicationVariants variants.all{variant-> if(!variant.buildType.isDebuggable()){ log.debug("Skippingnon-debuggablebuildtype'${variant.buildType.name}'.") return } JavaCompilejavaCompile=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"ajcargs:"+Arrays.toString(args) MessageHandlerhandler=newMessageHandler(true) newMain().run(args,handler) for(IMessagemessage:handler.getMessages(null,true)){ switch(message.getKind()){ caseIMessage.ABORT: caseIMessage.ERROR: caseIMessage.FAIL: log.errormessage.message,message.thrown break caseIMessage.WARNING: log.warnmessage.message,message.thrown break caseIMessage.INFO: log.infomessage.message,message.thrown break caseIMessage.DEBUG: log.debugmessage.message,message.thrown break } } } }
这一个gradle主要的东西就是这些:
//AOP面向切面编程,加入这行就不用在libs下引入jar包了,不然要写成compilefile(libs/aspectjrt.jar) compile'org.aspectj:aspectjrt:1.8.13' importorg.aspectj.bridge.IMessage importorg.aspectj.bridge.MessageHandler importorg.aspectj.tools.ajc.Main finaldeflog=project.logger finaldefvariants=project.android.applicationVariants variants.all{variant-> if(!variant.buildType.isDebuggable()){ log.debug("Skippingnon-debuggablebuildtype'${variant.buildType.name}'.") return } JavaCompilejavaCompile=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"ajcargs:"+Arrays.toString(args) MessageHandlerhandler=newMessageHandler(true) newMain().run(args,handler) for(IMessagemessage:handler.getMessages(null,true)){ switch(message.getKind()){ caseIMessage.ABORT: caseIMessage.ERROR: caseIMessage.FAIL: log.errormessage.message,message.thrown break caseIMessage.WARNING: log.warnmessage.message,message.thrown break caseIMessage.INFO: log.infomessage.message,message.thrown break caseIMessage.DEBUG: log.debugmessage.message,message.thrown break } } } }
下面那一堆是用命令在编译最后做一些关联的,具体的我也不懂,只管加上好了。
第二种
有多个module都需要用到aspectj,特别是组件开发的情况下,不可能每个module都配置一下,所以就需要新建一个aspectj的module作为项目的library。
app下build.gradle需要修改:
将
//AOP面向切面编程,加入这行就不用在libs下引入jar包了,不然要写成compilefile(libs/aspectjrt.jar) compile'org.aspectj:aspectjrt:1.8.13'
去掉,改为
implementationproject(':aspectjlib')
不过上面这句在你添加module依赖的时候会自动生成。
新建library的build.gradle配置如下:
applyplugin:'com.android.library' android{ compileSdkVersionrootProject.ext.compileSdkVersion buildToolsVersionrootProject.ext.buildToolsVersion defaultConfig{ minSdkVersionrootProject.ext.minSdkVersion targetSdkVersionrootProject.ext.targetSdkVersion versionCode1 versionName"1.0" testInstrumentationRunner"android.support.test.runner.AndroidJUnitRunner" } buildTypes{ release{ minifyEnabledfalse proguardFilesgetDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro' } } } dependencies{ implementationfileTree(dir:'libs',include:['*.jar']) implementationrootProject.ext.appcompatV7 testImplementation'junit:junit:4.12' androidTestImplementation'com.android.support.test:runner:1.0.1' androidTestImplementation'com.android.support.test.espresso:espresso-core:3.0.1' //AOP compile'org.aspectj:aspectjrt:1.8.13' } importorg.aspectj.bridge.IMessage importorg.aspectj.bridge.MessageHandler importorg.aspectj.tools.ajc.Main android.libraryVariants.all{variant-> JavaCompilejavaCompile=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)] MessageHandlerhandler=newMessageHandler(true) newMain().run(args,handler) deflog=project.logger for(IMessagemessage:handler.getMessages(null,true)){ switch(message.getKind()){ caseIMessage.ABORT: caseIMessage.ERROR: caseIMessage.FAIL: log.errormessage.message,message.thrown break caseIMessage.WARNING: caseIMessage.INFO: log.infomessage.message,message.thrown break caseIMessage.DEBUG: log.debugmessage.message,message.thrown break } } } }
注意:下面那一堆跟app的gradle中的稍微有点区别,一个是module,一个是library,gradle中的东西不一样。
两种配置方式基本就是这样了,使用方法我也是刚了解一点,记录一下简单的计算性能的用法吧
自定义注解类:
packagecom.test.qby.aspectjlib.annotation; importjava.lang.annotation.ElementType; importjava.lang.annotation.Retention; importjava.lang.annotation.RetentionPolicy; importjava.lang.annotation.Target; /** *Createdbyqbyon2018/1/260026. *自定义注解 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public@interfaceIFirstAnnotation{ Stringvalue(); }
@Target注解目标,表示注解使用在什么地方,这里是METHOD方法;@Retention保留策略,表示注解调用时机,这里RUNTIME运行时
切面类
importandroid.widget.Toast; importcom.test.qby.aspectjlib.annotation.IFirstAnnotation; importcom.test.qby.newtestapplication.app.MyApplication; importorg.aspectj.lang.ProceedingJoinPoint; importorg.aspectj.lang.annotation.Around; importorg.aspectj.lang.annotation.Aspect; importorg.aspectj.lang.annotation.Pointcut; importorg.aspectj.lang.reflect.MethodSignature; importjava.lang.reflect.Method; importjava.lang.reflect.TypeVariable; importjava.util.Locale; /** *Createdbyqbyon2018/1/260026. *自定义注解行为 */ @Aspect publicclassMethodBehaviorAspect{ privatestaticfinalStringTAG="aspect_aby"; @Pointcut("execution(@com.test.qby.aspectjlib.annotation.IFirstAnnotation**(..))") publicvoidfirstMethodAnnotationBehavior(){ } @Pointcut("execution(*com.test.qby.newtestapplication.ui.MainActivity.aspectClick(android.view.View))") publicvoidsecondMethodAnnotationBehavior(){ } @Around("firstMethodAnnotationBehavior()") publicObjectwavePointcutAround(ProceedingJoinPointjoinPoint)throwsThrowable{ MethodSignaturemethodSignature=(MethodSignature)joinPoint.getSignature(); //类名 StringclassName=methodSignature.getDeclaringType().getSimpleName(); //方法名 StringmethodName=methodSignature.getName(); //功能名 IFirstAnnotationbehaviorTrace=methodSignature.getMethod() .getAnnotation(IFirstAnnotation.class); Stringvalue=behaviorTrace.value(); //Stringvalue="点击"; longstart=System.currentTimeMillis(); Objectresult=joinPoint.proceed(); longduration=System.currentTimeMillis()-start; Log.e(TAG,String.format("%s类中%s方法执行%s功能,耗时:%dms",className,methodName,value,duration)); Toast.makeText(MyApplication.getContext(),String.format(Locale.CHINESE,"%s类中%s方法执行%s功能,耗时:%dms",className,methodName,value,duration),Toast.LENGTH_SHORT).show(); returnresult; } }
@Aspect指定切面类;@Pointcut切入点;@Around是切入方式Advice的一种,表示在切入点前后插入代码,还有@Before、@After;Pointcut语法,execution,表示根据Advice在执行方法内部代码前后插入代码,call,表示根据Advice在调用方法前后插入代码......
页面调用
@IFirstAnnotation("测试Aspect") publicvoidaspectClick(Viewview){ try{ Thread.sleep(newRandom().nextInt(1000)); }catch(InterruptedExceptione){ e.printStackTrace(); } }
@IFirstAnnotation调用注解,()内部为在IFirstAnnotation中写的value的值,去掉value()后此处去掉()
注意:在MethodBehaviorAspect类中如果有用到Context,可直接使用joinPoint.getTarget()类型转换成Context,这里是由于项目使用了databinding,部分getTarget()获取到的值不能强转为Context,所以这里用的MyApplication获取的Context
这只是个人的初步尝试,里面当然还有很多内容需要去学,刚看了CSDN上有人写的几篇关于AOP的内容,都挺详细的,给出其中一个地址,自己看吧:https://www.nhooo.com/article/110560.htm
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。