Android中aop的使用方式
项目运行了很长一段时间了,突然测试提了一个要求,说给很多地方要作防止重复点击:当时一听头大,这个好多地方,又想到说不定以后不是防止重复点击,要是判断网络了什么的,这不是更加头大,刚好之前学习aop突然想到这个可以直接用切面编程来作这个,下面介绍下Aop的使用方法:
首先,我们来导入aop的库:在build.gradle引入依赖:和在整个项目build.gradle中引入依赖:
implementation'org.aspectj:aspectjrt:1.8.13'
classpath'org.aspectj:aspectjtools:1.8.9'
classpath'org.aspectj:aspectjweaver:1.8.9'
在app包项目中引入:
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
final def log =project.logger
final def variants =project.android.applicationVariants
variants.all{ variant->
if (!variant.buildType.isDebuggable()) {
log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
return
}
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
}
}
}
}
下面介绍app的使用方式:
首先写一个注解用于和在我们醒目中点击事件的标记 如图:
然后自己处理一个切面:
该类中处理的方法就是:
处理两个方法分别是能处理当前标记的方法中处理的和处理系统所在的点击事件的处理地方:
@Aspect
public class AspectTest {
private StringTAG = AspectTest.class.getSimpleName();
private boolean isDoubleClick =false; // 用于判断是否重复点击
@Around("execution(@com.example.testutils.aop.DoubleClick * *(..))")
public void beforeEnableDoubleClcik(ProceedingJoinPoint joinPoint)throws Throwable {
//用于处理切点所在的类
Log.e(TAG, "beforeEnableDoubleClcik");
if (!NoDoubleClickUtils.isDoubleClick()) {
joinPoint.proceed();
Log.e(TAG, "onClickLitener");
}
}
@Around("execution(* android.view.View.OnClickListener.onClick(..))")
public void onClickLitener(ProceedingJoinPoint proceedingJoinPoint)throws Throwable {
// 用于处理切点标记的方法,和类
Log.e(TAG, "onClickLitener");
if (!NoDoubleClickUtils.isDoubleClick()) {
proceedingJoinPoint.proceed();
}
}
}
其中标记的地方是我们标记的注解(DoubleClick)所在的路径 :
这个地方是监听我们使用系统的onclick()所使用的地方:
这样我们就可以分别监听到我们使用系统的onClick事件的地方:
我们所标记的地方使用的DoubleClick的地方的点击事件:
其中我们下防止重复点击的事件工具类如下:
/**
* create at 2020/6/2
* author raotong
* Description : 防止按钮两次点击
*/
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 写的防止重复点击:
下面来介绍下这个库的一些注解的使用:
Advice(通知): 注入到class文件中的代码。典型的 Advice 类型有 before、after 和 around,分别表示在目标方法执行之前、执行后和完全替代目标方法执行的代码。 除了在方法中注入代码,也可能会对代码做其他修改,比如在一个class中增加字段或者接口。
Joint point(连接点): 程序中可能作为代码注入目标的特定的点,例如一个方法调用或者方法入口。
Pointcut(切入点): 告诉代码注入工具,在何处注入一段特定代码的表达式。例如,在哪些 joint points 应用一个特定的 Advice。切入点可以选择唯一一个,比如执行某一个方法,也可以有多个选择,比如,标记了一个定义成@DebguTrace 的自定义注解的所有方法。
Aspect(切面):Pointcut 和 Advice 的组合看做切面。例如,我们在应用中通过定义一个 pointcut 和给定恰当的advice,添加一个日志切面。
Weaving(织入): 注入代码(advices)到目标位置(joint points)的过程。
这就是以上的Aop的使用方式