史上最實用的Android切片應用庫XAOP使用指南

image

項目簡介

一個輕量級的AOP(Android)應用框架,囊括了最實用的AOP應用。項目地址: https://github.com/xuexiangjys/XAOP, 喜歡的話,歡迎star支持!android

設計起因

在咱們平時開發的過程當中,必定會遇到權限申請、線程切換、數據緩存、異常捕獲、埋點和方法執行時間統計等問題。這些都是很是常見的問題,實現起來也不是很難,不過就是太麻煩了,還會讓程序多出不少重複性、模版化的代碼。git

設計思路

讓我最初接觸到AOP思想的是JakeWharton的hugo,經過閱讀它的源碼以後,讓我對aspectj這項技術的動態代碼編織深深地着了迷。以後我詳細研究了aspectj相關的技術,並不斷蒐集AOP在Android上的典型應用場景,而後經過aspectj這項技術去逐一實現。最後就成就了XAOP這個庫。github

解決痛點

  • 解決快速點擊的問題
  • 解決Android6.0以上動態權限申請的問題
  • 線程自由切換的問題
  • 日誌埋點問題
  • 緩存問題(磁盤緩存和內存緩存)
  • 異常捕獲處理
  • 業務攔截(登錄驗證、有效性驗證等)

集成指南

添加Gradle依賴

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;
    }
});

兼容Kotlin語法配置

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("工做在主線程");
}

IO線程切片

  • IOThread屬性表
屬性名 類型 默認值 備註
value ThreadType ThreadType.Fixed 子線程的類型

1.使用@IOThread標註須要在io線程中執行的方法。可設置線程池的類型ThreadType,不設置的話默認是Fixed類型。

線程池的類型以下:

  • Single:單線程池
  • Fixed:多線程池
  • Disk:磁盤讀寫線程池(本質上是單線程池)
  • Network:網絡請求線程池(本質上是多線程池)

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業務攔截切片來實現。
  1. 定義業務攔截類型
// 登陸校驗攔截類型
public static final int INTERCEPT_LOGIN = 10;
  1. 定義攔截處理邏輯
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;
    }
});
  1. 在須要攔截的地方增長@Intercept標註
@Intercept(INTERCEPT_LOGIN)
public void doSomeThing() {
    ToastUtils.toast("已登錄過啦~~");
}

常見問題

接入的問題

使用前,請必定要仔細閱讀 集成指南,只要你每一步都參照文檔上寫的來接入,是不會有任何問題的!

1.問:個人項目是kotlin項目,我該怎麼使用?

答:kotlin項目的配置,只須要在原先項目的基礎上加上aspectjx 插件便可,詳情請參考兼容Kotlin語法配置

2.問:爲何我每次運行編譯時,一直報錯Invalid byte tag in constant pool,並且會自動生成一個ajcore.xxxxxxxxx.txt文件?

答:這裏頗有可能你的項目目前仍是使用的androidx版本,可是你使用的XAOP版本是support版本,致使編譯失敗。這裏須要強調的是,若是你的項目是support版本,請使用1.0.5版本;若是你的項目是androidx版本,請使用1.1.0及以上版本。

3.問:爲何我編譯都經過了,可是使用任何一個切片都沒有起任何做用?

答:這裏可能的緣由有兩個。

  • 1.你使用的XAOP版本和你的項目版本不匹配致使。好比你的項目是androidx版本,可是你卻使用XAOP的support版本,這樣瞎配的話,切片是不會起任何做用的。
  • 2.你忘記在項目的 build.gradle 中增長xaop插件的引用了。
apply plugin: 'com.xuexiang.xaop' //引用xaop插件

使用的問題

1.問:爲何我使用@SingleClick標註點擊的方法不起做用?

答:被@SingleClick標註的方法中,必定要有點擊控件View做爲方法參數,不然將不起做用。

2.問:爲何我使用@Permission標註的方法,返回值失效了?

答:因爲動態申請權限是一個異步的操做,因此被@Permission標註的方法是不能有返回值的。

配套設施

微信公衆號

更多資訊內容,歡迎微信搜索公衆號:「個人Android開源之旅」

相關文章
相關標籤/搜索