背景
接了个优化任务,对某个按键的多次点击进行优化,在阈值时间内多次点击只响应一次。
方案选择
考虑把这个事情做成通用的,而不是单独对某个点击事件生效。另外考虑到老代码兼容的问题,尽量选择侵入性小的方式来实现。所以aop的方式成为首选。
Aspectjx
Aop的一种方式,可以优雅地进行代码代码注入,在我们这个问题上,则可以将是否到达阈值时间的判断逻辑通过Aspectjx的方式进行代码注入。
具体操作
根目录下的build.gradle里dependencies添加
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.10'
这里有人sync的时候下不下来,可能是repositories里没有添加 jcenter(),如下所示
repositories {
google()
mavenCentral()
jcenter()
}
在使用到的模块的build.gradle下plugin里添加 id 'android-aspectjx',
如下:
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
id 'android-aspectjx'
}
这个时候sync一下 就已经可以使用Aspectjx了。
点击抖动的解决
Aspect的编写
@Aspect
public class InterceptAgainClickAOP {
@Pointcut("execution(void com..lambda*(android.view.View))")
public void dealWithLambda() {
}
@Pointcut("execution(void android.view.View.OnClickListener.onClick(..))")
public void dealWithNormal() {
}
private final String TAG = this.getClass().getSimpleName();
//上次点击的时间
private static Long sLastclick = 0L;
//拦截所有两次点击时间间隔小于一秒的点击事件
private static final Long FILTER_TIMEM = 1000L;
//上次点击事件View
private View lastView;
//---- add content -----
//是否过滤点击 默认是
private boolean checkClick = true;
//---- add content -----
//拦截所有* android.view.View.OnClickListener.onClick(..) 事件
//直接setOnclikListener 拦截点击事件
@Around("dealWithNormal()||dealWithLambda()")
public void clickFilterHook(ProceedingJoinPoint joinPoint) throws Throwable {
//大于指定时间
if (System.currentTimeMillis() - sLastclick >= FILTER_TIMEM) {
doClick(joinPoint);
} else {
//---- update content ----- 判断是否需要过滤点击
//小于指定秒数 但是不是同一个view 可以点击 或者不过滤点击
if (!checkClick ||lastView == null || lastView != (joinPoint).getArgs()[0]) {
//---- update content ----- 判断是否需要过滤点击
doClick(joinPoint);
} else {
//大于指定秒数 且是同一个view
Log.e("InterceptAgainClickAOP", "重复点击,已过滤");
}
}
}
//执行原有的 onClick 方法
private void doClick(ProceedingJoinPoint joinPoint) throws Throwable {
//判断 view 是否存在
if (joinPoint.getArgs().length == 0) {
joinPoint.proceed();
return;
}
//记录点击的 view
lastView = (View) (joinPoint).getArgs()[0];
//---- add content -----
//修改默认过滤点击
checkClick = true;
//---- add content -----
//记录点击事件
sLastclick = System.currentTimeMillis();
//执行点击事件
try {
joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
//标志不过滤点击
@Before("execution(@com.example.clickimprove.aop.UncheckClick * *(..))")
public void beforeuncheckClcik(JoinPoint joinPoint) throws Throwable {
Log.i(TAG, "beforeuncheckClcik");
//修改为不需要过滤点击
checkClick = false;
}
}
不需要拦截的注解
/**
* 标记不需要拦截点击
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface UncheckClick {
}
至此 sync一下就生效了 可以打个log看看生效没有
完了。