前言
切面编程一直是一个热点的话题,这篇文章讲讲一个第三方aop库在android上的应用。
本篇文章参考以下链接:
AOP第三方库
这章涉及到以下内容:
- aop库的配置
- aop导入问题解决
- aop的使用
- aop混淆
一. aop库的配置
在你的porject的build.gradle中做以下配置:
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0'
//AOP切面编程依赖
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:1.1.1'
classpath 'org.aspectj:aspectjtools:1.8.13'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
在 app module 的buildle.gradle中做如下配置:
//AOP切面编程依赖
compile 'com.safframework:saf-aop:1.2.0'
//rxjava2.x
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
compile 'io.reactivex.rxjava2:rxjava:2.1.0'
//AOP切面编程Cache依赖
implementation 'com.safframework:saf-cache:1.1.0'
implementation 'tony-common:tony-common-utils:1.2.4'
//AOP切面编程Log依赖
implementation 'com.safframework.log:saf-log:1.5.0'
//AOP切面编程AppPrefs依赖
implementation 'com.safframework.injectview:saf-injectview:1.0.0'
annotationProcessor 'com.safframework.injectview:saf-injectview-compiler:1.0.0'
需要注意的是,AOP库使用的时候,也要添加RxJava2.X的引用。
二. aop导入问题解决
在导入切面编程库依赖的时候,可能会出现如下问题:
Error:Execution failed for task ':app:transformClassesWithExtractJarsForDebug'.
> Unexpected scopes found in folder 'C:\my_demo_test\TestDemo\app\build\intermediates\transforms\AspectTransform\debug'.
Required: SUB_PROJECTS. Found:
EXTERNAL_LIBRARIES, PROJECT, SUB_PROJECTS
解决方案如下:
造成上述问题是由于as版本,需将Android studio的instant run关闭。具体如下:
Settings → Build, Execution, Deployment → Instant Run and uncheck Enable Instant Run.
配图如下:
解决此方法,大家也可以参考链接
android aspectJ报错“transformClassesWithExtractJarsForDebug“
三. aop的使用
AOP涉及的注解有以下几个:
下面对各注解依次讲解:
3.1 Async异步注解
使用类似如下:
@Async
private void AsyncTest(){
LogUtil.e("====当前线程===="+Thread.currentThread().getId());
LogUtil.e("====主线程===="+ Looper.getMainLooper().getThread().getId());
}
在主线程中调用 AsyncTest 方法,会发现其运行在一个不同于主线程的子线程中。
3.2 Cacheable缓存注解
存储数据如下:
@Cacheable(key = "name")
private String putCache(){
return "我是谁";
}
获取缓存数据:
private String getCache(){
Cache cache=Cache.get(CacheActivity.this);
//Cache的存取方式就是Acache,只不过存储地址改成了缓存而已
String name=cache.getString("name");
return name;
}
3.3 Log注解
你可以类似这样使用:
@LogMethod
private void log1(){
LogUtil.e("=====log1======");
}
@LogMethod
private String log2(String s){
LogUtil.e("=====log2======"+s);
return s;
}
然后在需要用到的地方直接调用 log1 和 log2 方法就可以打印log了,它最大的好处是不会在代码中穿插各种 Log代码。
3.4 Hook注解
使用范例:
@HookMethod(beforeMethod = "before",afterMethod = "after")
private void getMachine(){
LogUtil.e("======getMachine=====");
}
private void before(){
LogUtil.e("====开始时间=======");
}
private void after(){
LogUtil.e("====结束时间=======");
}
然后在调用getMachine方法的时候,你会收到这样的log
这个可以用来监测一个方法执行的用时,当然,你在声明Hook注解的时候必须包含 beforeMethod,afterMethod中的一个或同时具有,若不声明,则Hook使用无效
3.5 Prefs注解
类似手机上的文件存储,存值你可以这样操作:
@Prefs(key = "key")
private String putPrefs(){
return "大家好";
}
取值是这样的:
private String getPrefs(){
AppPrefs appPrefs=AppPrefs.get(PrefsActivity.this);
String key=appPrefs.getString("key",null);
return key;
}
3.6 safe注解
保证代码执行安全的,若不想代码抛出异常,你可以这样处理:
@Safe
private void testStringLength(){
String msg=null;
int length=msg.length();
}
这样,你在调用 testStringLength 方法的时候就不会报错了。
3.6 Trace注解
可以用来监测方法执行时长,使用时类似这样:
@Trace
private void testTrace(){
Observable.create(new ObservableOnSubscribe<String>() {
@Trace
@Override
public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
e.onNext("111");
}
}).subscribe(new Consumer<String>() {
@Trace
@Override
public void accept(@NonNull String str) throws Exception {
}
});
}
调用 testTrace 方法之后,在log 的 i 级别中,你可以看到这样的log
这里,我们就可以很清楚的看到每个方法的执行时间了。
四. 混淆
混淆的话,可以这样处理
-keep class com.safframework.aop.** { *; }
ok,今天就讲到这里,谢谢诶。