一個輕量級的AOP(Android)應用框架,囊括了最實用的AOP應用。項目地址: https://github.com/xuexiangjys/XAOP, 喜歡的話,歡迎star支持!android
在咱們平時開發的過程當中,必定會遇到權限申請、線程切換、數據緩存、異常捕獲、埋點和方法執行時間統計等問題。這些都是很是常見的問題,實現起來也不是很難,不過就是太麻煩了,還會讓程序多出不少重複性、模版化的代碼。git
讓我最初接觸到AOP思想的是JakeWharton的hugo,經過閱讀它的源碼以後,讓我對aspectj這項技術的動態代碼編織深深地着了迷。以後我詳細研究了aspectj相關的技術,並不斷蒐集AOP在Android上的典型應用場景,而後經過aspectj這項技術去逐一實現。最後就成就了XAOP這個庫。github
1.先在項目根目錄的 build.gradle
的 repositories 添加:數組
allprojects { repositories { ... maven { url "https://jitpack.io" } } }
2.再在項目根目錄的 build.gradle
的 dependencies 添加xaop插件:緩存
buildscript { ··· dependencies { ··· classpath 'com.github.xuexiangjys.XAOP:xaop-plugin:1.1.0' } }
3.在項目的 build.gradle
中增長依賴並引用xaop插件微信
apply plugin: 'com.xuexiang.xaop' //引用xaop插件 dependencies { ··· //若是是androidx項目,使用1.1.0版本及以上 implementation 'com.github.xuexiangjys.XAOP:xaop-runtime:1.1.0' //若是是support項目,請使用1.0.5版本 implementation 'com.github.xuexiangjys.XAOP:xaop-runtime:1.0.5' }
4.在Application
中進行初始化網絡
XAOP.init(this); //初始化插件 XAOP.debug(true); //日誌打印切片開啓 XAOP.setPriority(Log.INFO); //設置日誌打印的等級,默認爲0 //設置動態申請權限切片 申請權限被拒絕的事件響應監聽 XAOP.setOnPermissionDeniedListener(new PermissionUtils.OnPermissionDeniedListener() { @Override public void onDenied(List<String> permissionsDenied) { // 權限申請被拒絕的處理 } }); //設置自定義攔截切片的處理攔截器 XAOP.setInterceptor(new Interceptor() { @Override public boolean intercept(int type, JoinPoint joinPoint) throws Throwable { XLogger.d("正在進行攔截,攔截類型:" + type); switch(type) { case 1: //作你想要的攔截 break; case 2: return true; //return true,直接攔截切片的執行 default: break; } return false; } }); //設置自動捕獲異常的處理者 XAOP.setIThrowableHandler(new IThrowableHandler() { @Override public Object handleThrowable(String flag, Throwable throwable) { XLogger.d("捕獲到異常,異常的flag:" + flag); if (flag.equals(TRY_CATCH_KEY)) { return 100; } return null; } });
1.在項目根目錄的 build.gradle
的 dependencies 添加 aspectjx 插件:多線程
buildscript { ··· dependencies { ··· classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.10' } }
2.在項目的 build.gradle
中增長依賴並引用 aspectjx 插件app
apply plugin: 'android-aspectjx' //引用aspectjx插件 aspectjx { include '項目的applicationId' }
詳細使用可參見 kotlin-test 項目進行使用.框架
-keep @com.xuexiang.xaop.annotation.* class * {*;} -keep @org.aspectj.lang.annotation.* class * {*;} -keep class * { @com.xuexiang.xaop.annotation.* <fields>; @org.aspectj.lang.annotation.* <fields>; } -keepclassmembers class * { @com.xuexiang.xaop.annotation.* <methods>; @org.aspectj.lang.annotation.* <methods>; }
SingleClick
屬性表屬性名 | 類型 | 默認值 | 備註 |
---|---|---|---|
value | long | 1000 | 快速點擊的間隔(ms) |
1.使用@SingleClick
標註點擊的方法。注意點擊的方法中必定要有點擊控件View做爲方法參數,不然將不起做用。
2.能夠設置快速點擊的時間間隔,單位:ms。不設置的話默認是1000ms。
@SingleClick(5000) public void handleOnClick(View v) { XLogger.e("點擊響應!"); ToastUtil.get().toast("點擊響應!"); hello("xuexiangjys", "666666"); }
Permission
屬性表屬性名 | 類型 | 默認值 | 備註 |
---|---|---|---|
value | String[] | / | 須要申請權限的集合 |
1.使用@Permission
標註須要申請權限執行的方法。可設置申請一個或多個權限。
2.使用@Permission
標註的方法,在執行時會自動判斷是否須要申請權限。
@SingleClick @Permission({PermissionConsts.CALENDAR, PermissionConsts.CAMERA, PermissionConsts.LOCATION}) private void handleRequestPermission(View v) { }
1.使用@MainThread
標註須要在主線程中執行的方法。
2.使用@MainThread
標註的方法,在執行時會自動切換至主線程。
@MainThread private void doInMainThread(View v) { mTvHello.setText("工做在主線程"); }
IOThread
屬性表屬性名 | 類型 | 默認值 | 備註 |
---|---|---|---|
value | ThreadType | ThreadType.Fixed | 子線程的類型 |
1.使用@IOThread
標註須要在io線程中執行的方法。可設置線程池的類型ThreadType
,不設置的話默認是Fixed類型。
線程池的類型以下:
2.使用@IOThread
標註的方法,在執行時會自動切換至指定類型的io線程。
@IOThread(ThreadType.Single) private String doInIOThread(View v) { return "io線程名:" + Thread.currentThread().getName(); }
DebugLog
屬性表屬性名 | 類型 | 默認值 | 備註 |
---|---|---|---|
priority | int | 0 | 日誌的優先級 |
1.使用@DebugLog
標註須要打印的方法和類。可設置打印的優先級,不設置的話默認優先級爲0。注意:若是打印的優先級比XAOP.setPriority
設置的優先級小的話,將不會進行打印。
2.使用@DebugLog
標註的類和方法在執行的過程當中,方法名、參數、執行的時間以及結果都將會被打印。
3.可調用XAOP.setISerializer
設置打印時序列化參數對象的序列化器。
4.可調用XAOP.setLogger
設置打印的實現接口。默認提供的是突破4000限制的logcat日誌打印。
@DebugLog(priority = Log.ERROR) private String hello(String name, String cardId) { return "hello, " + name + "! Your CardId is " + cardId + "."; }
MemoryCache
屬性表屬性名 | 類型 | 默認值 | 備註 |
---|---|---|---|
value | String | "" | 內存緩存的key |
enableEmpty | boolean | true | 對於String、數組和集合等,是否容許緩存爲空 |
1.使用@MemoryCache
標註須要內存緩存的方法。可設置緩存的key,不設置的話默認key爲方法名(參數1名=參數1值|參數2名=參數2值|...)
,固然你也能夠修改key的自動生成規則,你只須要調用XAOP.setICacheKeyCreator
便可。
2.標註的方法必定要有返回值,不然內存緩存切片將不起做用。
3.使用@MemoryCache
標註的方法,可自動實現緩存策略。默認使用的內存緩存是LruCache
。
4.可調用XAOP.initMemoryCache
設置內存緩存的最大數量。默認是Runtime.getRuntime().maxMemory() / 1024) / 8
@MemoryCache private String hello(String name, String cardId) { return "hello, " + name + "! Your CardId is " + cardId + "."; }
DiskCache
屬性表屬性名 | 類型 | 默認值 | 備註 |
---|---|---|---|
value | String | "" | 內存緩存的key |
cacheTime | long | -1 | 緩存時間【單位:s】,默認是永久有效 |
enableEmpty | boolean | true | 對於String、數組和集合等,是否容許緩存爲空 |
1.使用@DiskCache
標註須要磁盤緩存的方法。可設置緩存的key,不設置的話默認key爲方法名(參數1名=參數1值|參數2名=參數2值|...)
,固然你也能夠修改key的自動生成規則,你只須要調用XAOP.setICacheKeyCreator
便可。
2.可設置磁盤緩存的有效期,單位:s。不設置的話默認永久有效。
3.標註的方法必定要有返回值,不然磁盤緩存切片將不起做用。
4.使用@DiskCache
標註的方法,可自動實現緩存策略。默認使用的磁盤緩存是JakeWharton的DiskLruCache
。
5.可調用XAOP.initDiskCache
設置磁盤緩存的屬性,包括磁盤序列化器IDiskConverter
,磁盤緩存的根目錄,磁盤緩存的最大空間等。
@DiskCache private String hello(String name, String cardId) { return "hello, " + name + "! Your CardId is " + cardId + "."; }
Safe
屬性表屬性名 | 類型 | 默認值 | 備註 |
---|---|---|---|
value | String | "" | 捕獲異常的標誌 |
1.使用@Safe
標註須要進行異常捕獲的方法。可設置一個異常捕獲的標誌Flag,默認的Flag爲當前類名.方法名
。
2.調用XAOP.setIThrowableHandler
設置捕獲異常的自定義處理者,可實現對異常的彌補處理。若是不設置的話,將只打印異常的堆棧信息。
3.使用@Safe
標註的方法,可自動進行異常捕獲,並統一進行異常處理,保證方法平穩執行。
@Safe(TRY_CATCH_KEY) private int getNumber() { return 100 / 0; }
Intercept
屬性表屬性名 | 類型 | 默認值 | 備註 |
---|---|---|---|
value | int[] | / | 攔截類型 |
1.使用@Intercept
標註須要進行攔截的方法和類。可設置申請一個或多個攔截類型。
2.若是不調用XAOP.setInterceptor
設置切片攔截的攔截器的話,自定義攔截切片將不起做用。
3.使用@Intercept
標註的類和方法,在執行時將自動調用XAOP
設置的攔截器進行攔截處理。若是攔截器處理返回true的話,該類或方法的執行將被攔截,不執行。
4.使用@Intercept
能夠靈活地進行切片攔截。好比用戶登陸權限等。
@SingleClick(5000) @DebugLog(priority = Log.ERROR) @Intercept(3) public void handleOnClick(View v) { XLogger.e("點擊響應!"); ToastUtil.get().toast("點擊響應!"); hello("xuexiangjys", "666666"); } @DebugLog(priority = Log.ERROR) @Intercept({1,2,3}) private String hello(String name, String cardId) { return "hello, " + name + "! Your CardId is " + cardId + "."; }
【注意】:當有多個切片註解修飾時,通常是從上至下依次順序執行。
在應用中,對於部分功能,如:我的中心、錢包、收藏等須要咱們驗證登陸的功能,咱們均可以經過
@Intercept
業務攔截切片來實現。
// 登陸校驗攔截類型 public static final int INTERCEPT_LOGIN = 10;
XAOP.setInterceptor(new Interceptor() { @Override public boolean intercept(int type, JoinPoint joinPoint) throws Throwable { switch(type) { case INTERCEPT_LOGIN: if (!LoginActivity.sIsLogined) { //沒登陸,進行攔截 ToastUtils.toast("請先進行登錄!"); ActivityUtils.startActivity(LoginActivity.class); return true; //return true,直接攔截切片的執行 } break; default: break; } return false; } });
@Intercept
標註@Intercept(INTERCEPT_LOGIN) public void doSomeThing() { ToastUtils.toast("已登錄過啦~~"); }
使用前,請必定要仔細閱讀 集成指南,只要你每一步都參照文檔上寫的來接入,是不會有任何問題的!
答:kotlin項目的配置,只須要在原先項目的基礎上加上aspectjx 插件便可,詳情請參考兼容Kotlin語法配置 。
Invalid byte tag in constant pool
,並且會自動生成一個ajcore.xxxxxxxxx.txt
文件?答:這裏頗有可能你的項目目前仍是使用的androidx版本,可是你使用的XAOP版本是support版本,致使編譯失敗。這裏須要強調的是,若是你的項目是support版本,請使用1.0.5版本;若是你的項目是androidx版本,請使用1.1.0及以上版本。
答:這裏可能的緣由有兩個。
build.gradle
中增長xaop插件的引用了。apply plugin: 'com.xuexiang.xaop' //引用xaop插件
@SingleClick
標註點擊的方法不起做用?答:被@SingleClick
標註的方法中,必定要有點擊控件View做爲方法參數,不然將不起做用。
@Permission
標註的方法,返回值失效了?答:因爲動態申請權限是一個異步的操做,因此被@Permission
標註的方法是不能有返回值的。
更多資訊內容,歡迎微信搜索公衆號:「個人Android開源之旅」