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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。