第一次接触到aop大概是16年底的时候,那时候负责对接期货开户sdk,老大想破解其中期货公司展示的名字,问了下同行,说利用aop来实现,当时看了一周完成了业务的开发,也没有过多的思考aop在安卓开发中其他的用处,所以后期不了了之了。近期在坐地铁在掘金上偶然看到一篇介绍安卓中aop使用的文章,又拾起了对aop的兴趣,所以将自己在项目中的一些实践分享给大家
——————————————————————————————————————————————————————————————————————————————————————————————————————————————————
先贴下载地址:https://download.csdn.net/download/wcsandlili/11182554
1、要想使用aop,必须得引入,目前安卓这一块使用最多的还是AspectJ,看网上各位大佬都说沪江的地址比较稳定,所以我也是引用的,①在项目的classPath添加
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.4'
②在app的gradle里面添加引用
implementation ‘org.aspectj:aspectjrt:1.8.13’
或者添加插件
apply plugin: 'android-aspectjx'
好了,至此aop的引入已经完成,我们可以接下来执行我们的开发了
2、(点击事件拦截处理)要想aop在项目里面能生效,我们首先得创建一个能被aop识别的文件,也就是创建一个class,添加@Aspect的注解
如下
我们第一步要创建一个能被aop识别的快速连点过滤的方法,也就是让aop能拦截到我们的点击的方法,这点有点像okhttp的拦截器Interceptor,拦截到我们点击的事件来自动过滤,那么怎么才能拦截?我们通过aop的环绕行@Around来进行安卓原生点击事件的处理,关于aop的一些基本注解和语法建议各位大佬自己在别的博客中查看下,这样理解起来更加的方便,直接给出拦截的方法
@Around("execution(* android.view.View.OnClickListener.onClick(..))") //其实就是拦截安卓原生的点击方法
如果不考虑双击的话用第一个注释的方法,NoDoubleClickUtils就是通过两次点击事件来判断是否过滤掉事件
public class NoDoubleClickUtils {
private final static int SPACE_TIME = 500;//2次点击的间隔时间,单位ms
private static long lastClickTime;
public synchronized static boolean isDoubleClick() {
long currentTime = System.currentTimeMillis();
boolean isClick;
if (currentTime - lastClickTime > SPACE_TIME) {
isClick = false;
} else {
isClick = true;
}
lastClickTime = currentTime;
return isClick;
}
}
下面的代码是aop中拦截快速连点的处理的方法,其中的 proceedingJoinPoint.proceed();是判断事件能否继续执行下去,如果没有这行代码,相当于我们的事件就此拦截,不能继续执行下去了
@Around("execution(* android.view.View.OnClickListener.onClick(..))")
public void onClickLitener(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
if (BuildConfig.DEBUG) {
LogUtils.e(TAG, "OnClick单击");
}
//只考虑单击
// if (!NoDoubleClickUtils.isDoubleClick()) {
// proceedingJoinPoint.proceed();
// }
//考虑双击控制
if (isDoubleClick || !NoDoubleClickUtils.isDoubleClick()) {
proceedingJoinPoint.proceed();
isDoubleClick = false;
}
}
方法拦截日志打印
为了支持特定的界面能执行双击的响应,我们可以通过自定义注解来实现,标记一个全局的变量,通过上面的isDoubleClick来控制判断,代码如下,在需要的地方添加@DoubleClick来实现和拦截
/**
* 双击自定义注解
*/
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface DoubleClick {
}
使用自定义注解,该点击事件下面全部都能响应双击事件了
不添加注解的话默认拦截所有的双击事件(至此项目双击的处理与否已经处理完成)
》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
3、(动态权限拦截处理<配合Rxpermission处理>)
我们拦截动态权限为了获取到声明的权限,所以在自定义注解里面定义一个String[]数组来接受声明的多个权限,注解如下
/**
* Created by WinWang on 2019/5/15
* Description->
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestPermissions {
String[] value();
}
在aop里面通过拦截我们的自定义注解来实现权限的校验,判断继续执行的方法与否
@Around("call(* *..*.*(..)) && @annotation(requestPermissions)")
public void requestPermissions(final ProceedingJoinPoint proceedingJoinPoint, RequestPermissions requestPermissions) throws Exception {
if (BuildConfig.DEBUG) {
Log.d(TAG, "----------request permission");
}
String[] permissions = requestPermissions.value(); //获取到注解里的权限数组
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
try {
proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return;
}
Object target = proceedingJoinPoint.getTarget();
FragmentActivity activity = null;
if (target instanceof Activity) {
activity = (FragmentActivity) target;
} else if (target instanceof Fragment) {
activity = ((Fragment) target).getActivity();
}
RxPermissions rxPermissions = new RxPermissions(activity);
final Activity finalActivity = activity;
rxPermissions.request(permissions)
.subscribe(new Consumer<Boolean>() {
@Override
public void accept(Boolean granted) throws Exception {
if (granted) {
try {
proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
} else {
Toast.makeText(finalActivity, "未获取到权限,不能继续操作", Toast.LENGTH_LONG).show();
}
}
});
}
项目中动态权限的使用
就是这么简单,一行代码能实现,不用再去关心每个权限响应的回调了
好了,aop在安卓中的双击过滤以及动态权限的介绍基本也就这么多了,如果想设计更多的操作,希望各位大佬能根据此demo举一反三,运用在自己的项目中,比如全局动态埋点的实现