您好,登錄后才能下訂單哦!
前言
之前了解過android的AOP框架,用法主要用來打日志;現(xiàn)在有一個需求需要函數(shù)在新線程中執(zhí)行,并且函數(shù)主體執(zhí)行完之后,在UI線程返回結(jié)果。想到手寫的話,每次都要new Thread的操作,比較麻煩;因此就嘗試用注解的方法解決這個問題。
AspectJ的使用核心就是它的編譯器,它就做了一件事,將AspectJ的代碼在編譯期插入目標(biāo)程序當(dāng)中,運(yùn)行時跟在其它地方?jīng)]什么兩樣,因此要使用它最關(guān)鍵的就是使用它的編譯器去編譯代碼ajc。ajc會構(gòu)建目標(biāo)程序與AspectJ代碼的聯(lián)系,在編譯期將AspectJ代碼插入被切出的PointCut中,已達(dá)到AOP的目的。
因此,無論在什么IDE上(如果使用命令行就可以直接使用ajc編譯了),問題就是讓IDE使用ajc作為編譯器編譯代碼。
代碼實(shí)現(xiàn)
注解使用
代碼主要通過TraceLog、RunOnNewThread、RunOnNewThreadWithUICallback這三個注解與AOP容器關(guān)聯(lián)。使用方法如下:
@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方法,希望方法體在一個新的線程執(zhí)行并打印方法執(zhí)行的Log;isShowTipsForFirstVideoCache方法,希望方法體在一個新的線程執(zhí)行,并將函數(shù)的結(jié)果通過DBQueryCallback這個回調(diào)回傳給UI線程,同時打印方法執(zhí)行的Log。
AOP容器識別這三個注解,并實(shí)現(xiàn)注解解釋器。
@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()); } }
使用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這個注解的匹配規(guī)則需要函數(shù)的最后一個參數(shù)為DBQueryCallback(必須要有一個回調(diào)參數(shù),不然怎么回傳給UI線程~)。函數(shù)的返回值必須和DBQueryCallback的泛型類型一致,因?yàn)樾枰獙⒎祷刂祩魅牖卣{(diào)當(dāng)中;
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();,執(zhí)行了函數(shù)體以后,我們默認(rèn)取到的是一個Object類型的返回值,所以不能用基本數(shù)據(jù)類型(bool用Boolean,int用Interger)。還有一點(diǎn),Java中的null是可以轉(zhuǎn)化為任意類型的,所以就算在函數(shù)體直接返回null,執(zhí)行final Object obj = joinPoint.proceed();,這個類型轉(zhuǎn)化也是不會有問題。親測有效,可以放心使用
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。