AndroidStudio 配置 AspectJ 環(huán)境實(shí)現(xiàn)AOP的方法
昨天看了一段android配置aspectj實(shí)現(xiàn)AOP的直播視頻,就試著自己配置了一下,可能是因?yàn)槲易约旱腁ndroidStudio環(huán)境的問題,碰到了不少的坑(其實(shí)還是因?yàn)閷?duì)gradle理解的不多),但總歸是配置好了,就分享一下。
試了兩種方式,不過項(xiàng)目下的build.gradle,沒什么變化,直接看一下代碼吧:
build.gradle(項(xiàng)目下)
buildscript { ext { //android appcompat支持庫(kù)版本 androidSupportVersion = '26.1.0' //編譯的 SDK 版本,如API20 compileSdkVersion = 26 //構(gòu)建工具的版本,其中包括了打包工具aapt、dx等,如API20對(duì)應(yīng)的build-tool的版本就是20.0.0 buildToolsVersion = "26.0.2" //兼容的最低 SDK 版本 minSdkVersion = 15 //向前兼容,保存新舊兩種邏輯,并通過 if-else 方法來判斷執(zhí)行哪種邏輯 targetSdkVersion = 26 //kotlin版本號(hào) 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: Do not place your application dependencies here; they belong // in the individual module build.gradle files classpath 'org.aspectj:aspectjtools:1.8.13' classpath 'org.aspectj:aspectjweaver:1.8.13' } } allprojects { repositories { google() jcenter() mavenCentral() } } task clean(type: Delete) { delete rootProject.buildDir }
看著一大堆,主要就是下面這幾行配置,其他的是我自己項(xiàng)目中用到的,根據(jù)自己需要配置就行。
buildscript { repositories { mavenCentral() } dependencies { classpath 'org.aspectj:aspectjtools:1.8.13' classpath 'org.aspectj:aspectjweaver:1.8.13' } } repositories { mavenCentral() }
其實(shí)這幾行配置在app的build.gradle里也是可以的,但是因?yàn)轫?xiàng)目下的build.gradle里已經(jīng)有buildscript {}、allprojects {repositories{} },就配置在這里了。
然后有兩種配置方式:
第一種
只有一個(gè)主Module app的情況下,配置app的build.gradle:
apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'org.greenrobot.greendao' android { compileSdkVersion rootProject.ext.compileSdkVersion buildToolsVersion rootProject.ext.buildToolsVersion defaultConfig { applicationId "填入自己的applicationId" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0" //Lambda配置 // jackOptions.enabled = true // android.compileOptions.sourceCompatibility 1.8 buildConfigField "boolean", "LOG", "true"http:// 顯示Log testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" //支持矢量圖 vectorDrawables.useSupportLibrary = true ndk { //選擇要添加的對(duì)應(yīng)cpu類型的.so庫(kù)。 abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64', 'mips', 'mips64' } } buildTypes { release { minifyEnabled false buildConfigField "boolean", "LOG", "false"http:// 顯示Log proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } //Lambda配置 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } dataBinding { enabled true } greendao { schemaVersion 1//數(shù)據(jù)庫(kù)版本號(hào) daoPackage 'com.test.qby.newtestapplication.greendao'//設(shè)置DaoMaster、DaoSession、Dao包名 targetGenDir 'src/main/java'//設(shè)置DaoMaster、DaoSession、Dao目錄 //targetGenDirTest:設(shè)置生成單元測(cè)試目錄 //generateTests:設(shè)置自動(dòng)生成單元測(cè)試用例 } lintOptions { abortOnError true } } dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation rootProject.ext.kotlinVersion implementation rootProject.ext.appcompatV7 implementation rootProject.ext.constraintLayout compile rootProject.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' // If you want to use the GPU Filters 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' // Because RxAndroid releases are few and far between, it is recommended you also // explicitly depend on RxJava's latest version for bug fixes and new features. 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包了,不然要寫成compile file(libs/aspectjrt.jar) compile 'org.aspectj:aspectjrt:1.8.13' } /* //在項(xiàng)目下配置了,此處就不需要了 buildscript { repositories { mavenCentral() } dependencies { classpath 'org.aspectj:aspectjtools:1.8.13' classpath 'org.aspectj:aspectjweaver:1.8.13' } } repositories { mavenCentral() } */ import org.aspectj.bridge.IMessage import org.aspectj.bridge.MessageHandler import org.aspectj.tools.ajc.Main 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.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 } } } }
這一個(gè)gradle主要的東西就是這些:
//AOP面向切面編程,加入這行就不用在libs下引入jar包了,不然要寫成compile file(libs/aspectjrt.jar) compile 'org.aspectj:aspectjrt:1.8.13' import org.aspectj.bridge.IMessage import org.aspectj.bridge.MessageHandler import org.aspectj.tools.ajc.Main 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.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 } } } }
下面那一堆是用命令在編譯最后做一些關(guān)聯(lián)的,具體的我也不懂,只管加上好了。
第二種
有多個(gè)module都需要用到aspectj,特別是組件開發(fā)的情況下,不可能每個(gè)module都配置一下,所以就需要新建一個(gè)aspectj的module作為項(xiàng)目的library。
app下build.gradle需要修改:
將
//AOP面向切面編程,加入這行就不用在libs下引入jar包了,不然要寫成compile file(libs/aspectjrt.jar) compile 'org.aspectj:aspectjrt:1.8.13'
去掉,改為
implementation project(':aspectjlib')
不過上面這句在你添加module依賴的時(shí)候會(huì)自動(dòng)生成。
新建library的build.gradle配置如下:
apply plugin: 'com.android.library' android { compileSdkVersion rootProject.ext.compileSdkVersion buildToolsVersion rootProject.ext.buildToolsVersion defaultConfig { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation rootProject.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' } import org.aspectj.bridge.IMessage import org.aspectj.bridge.MessageHandler import org.aspectj.tools.ajc.Main android.libraryVariants.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", android.bootClasspath.join( File.pathSeparator)] MessageHandler handler = new MessageHandler(true) new Main().run(args, handler) def log = project.logger 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: case IMessage.INFO: log.info message.message, message.thrown break case IMessage.DEBUG: log.debug message.message, message.thrown break } } } }
注意:下面那一堆跟app的gradle中的稍微有點(diǎn)區(qū)別,一個(gè)是module,一個(gè)是library,gradle中的東西不一樣。
兩種配置方式基本就是這樣了,使用方法我也是剛了解一點(diǎn),記錄一下簡(jiǎn)單的計(jì)算性能的用法吧
自定義注解類:
package com.test.qby.aspectjlib.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Created by qby on 2018/1/26 0026. * 自定義注解 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface IFirstAnnotation { String value(); }
@Target 注解目標(biāo),表示注解使用在什么地方,這里是METHOD方法;@Retention 保留策略,表示注解調(diào)用時(shí)機(jī),這里RUNTIME運(yùn)行時(shí)
切面類
import android.widget.Toast; import com.test.qby.aspectjlib.annotation.IFirstAnnotation; import com.test.qby.newtestapplication.app.MyApplication; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import java.lang.reflect.Method; import java.lang.reflect.TypeVariable; import java.util.Locale; /** * Created by qby on 2018/1/26 0026. * 自定義注解行為 */ @Aspect public class MethodBehaviorAspect { private static final String TAG = "aspect_aby"; @Pointcut("execution(@com.test.qby.aspectjlib.annotation.IFirstAnnotation * *(..))") public void firstMethodAnnotationBehavior() { } @Pointcut("execution(* com.test.qby.newtestapplication.ui.MainActivity.aspectClick(android.view.View))") public void secondMethodAnnotationBehavior() { } @Around("firstMethodAnnotationBehavior()") public Object wavePointcutAround(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); // 類名 String className = methodSignature.getDeclaringType().getSimpleName(); // 方法名 String methodName = methodSignature.getName(); // 功能名 IFirstAnnotation behaviorTrace = methodSignature.getMethod() .getAnnotation(IFirstAnnotation.class); String value = behaviorTrace.value(); // String value = "點(diǎn)擊"; long start = System.currentTimeMillis(); Object result = joinPoint.proceed(); long duration = System.currentTimeMillis() - start; Log.e(TAG, String.format("%s類中%s方法執(zhí)行%s功能,耗時(shí):%dms", className, methodName, value, duration)); Toast.makeText(MyApplication.getContext(), String.format(Locale.CHINESE, "%s類中%s方法執(zhí)行%s功能,耗時(shí):%dms", className, methodName, value, duration), Toast.LENGTH_SHORT).show(); return result; } }
@Aspect指定切面類;@Pointcut切入點(diǎn);@Around是切入方式Advice的一種,表示在切入點(diǎn)前后插入代碼,還有@Before、@After;Pointcut語(yǔ)法,execution,表示根據(jù)Advice在執(zhí)行方法內(nèi)部代碼前后插入代碼,call,表示根據(jù)Advice在調(diào)用方法前后插入代碼......
頁(yè)面調(diào)用
@IFirstAnnotation("測(cè)試Aspect") public void aspectClick(View view) { try { Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } }
@IFirstAnnotation調(diào)用注解,()內(nèi)部為在IFirstAnnotation中寫的value的值,去掉value()后此處去掉()
注意:在MethodBehaviorAspect 類中如果有用到Context,可直接使用joinPoint.getTarget()類型轉(zhuǎn)換成Context,這里是由于項(xiàng)目使用了databinding,部分getTarget()獲取到的值不能強(qiáng)轉(zhuǎn)為Context,所以這里用的MyApplication獲取的Context
這只是個(gè)人的初步嘗試,里面當(dāng)然還有很多內(nèi)容需要去學(xué),剛看了CSDN上有人寫的幾篇關(guān)于AOP的內(nèi)容,都挺詳細(xì)的,給出其中一個(gè)地址,自己看吧:http://www.dbjr.com.cn/article/110560.htm
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android實(shí)現(xiàn)啟動(dòng)頁(yè)倒計(jì)時(shí)效果
這篇文章主要介紹了Android實(shí)現(xiàn)啟動(dòng)頁(yè)倒計(jì)時(shí)效果的示例代碼,幫助大家更好的理解和學(xué)習(xí)使用Android進(jìn)行開發(fā),感興趣的朋友可以了解下2021-04-04Flutter實(shí)現(xiàn)固定header底部滑動(dòng)頁(yè)效果示例
這篇文章主要為大家介紹了Flutter實(shí)現(xiàn)固定header底部滑動(dòng)頁(yè)效果示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12Android OkHttp Post上傳文件并且攜帶參數(shù)實(shí)例詳解
這篇文章主要介紹了Android OkHttp Post上傳文件并且攜帶參數(shù)實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-03-03android studio 3.6.0 綁定視圖新特性的方法
這篇文章主要介紹了android studio 3.6.0 綁定視圖新特性的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04Android調(diào)試神器stetho使用詳解和改造
今天小編就為大家分享一篇關(guān)于Android調(diào)試神器stetho使用詳解和改造,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-02-02android防止提交事件時(shí)觸發(fā)多個(gè)表單中的按鈕
這篇文章主要介紹了android防止提交事件時(shí)觸發(fā)多個(gè)表單中的按鈕,2015-05-05Android 實(shí)現(xiàn)定時(shí)任務(wù)的過程詳解
這篇文章主要介紹了Android 定時(shí)任務(wù)過程詳解的相關(guān)資料,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11Flutter自定義下拉刷新時(shí)的loading樣式的方法詳解
Flutter中的下拉刷新,我們通常RefreshIndicator,可以通過color或strokeWidth設(shè)置下拉刷新的顏色粗細(xì)等樣式,但如果要自定義自己的widget,RefreshIndicator并沒有暴露出對(duì)應(yīng)的屬性,那如何修改呢,文中給大家介紹的非常詳細(xì),需要的朋友可以參考下2024-01-01