在开发的过程中,我们常常会遇到这样的需求,当用户过快的点击按钮时,只响应一次点击事件。
通常的做法是用一个变量记录上次点击的时间,然后取当前的时间和上次的点击时间的差值,只有大于预定的时间才会响应。
以下是我的几种实现方法,包括两类,一类是普通的做法,另外一类是用AspectJ加入切面来实现,实现起来更加的优雅。
1.普通做法
1.1实现方式一
1.建立一个父类,在父类里面实现是否拦截点击事件的判断
public class BaseActivity extends AppCompatActivity {
private static long clickGapTime = 0;
public static final int CLICK_GAP_RESPONSE = 500;//500ms内不响应
protected boolean clickGapFilter(){
long currentTimeMillis = System.currentTimeMillis();
if(currentTimeMillis-clickGapTime< CLICK_GAP_RESPONSE){
return false;
}
clickGapTime = currentTimeMillis;
return true;
}
}
2.继承这个父类,然后在点击事件里面判断是否满足条件,只有满足了clickGapFilter才能够继续执行
btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(clickGapFilter()){
//执行任务
Toast.makeText(MainActivity.this,"点击事件",Toast.LENGTH_SHORT).show();
}
}
});
1.2实现方式二
1.创建一个抽象类,实现View.OnClickListener的方法,有一个抽象方法gapClick,只有当点击间隔大于500ms的时候才会执行gapClick函数。
public abstract class ClickGapListener implements View.OnClickListener{
private static long clickGapTime = 0;
public static final int CLICK_GAP_RESPONSE = 500;//500ms内不响应
@Override
public void onClick(View view) {
long currentTimeMillis = System.currentTimeMillis();
if(currentTimeMillis-clickGapTime > CLICK_GAP_RESPONSE){
clickGapTime = currentTimeMillis;
gapClick();
}
}
protected abstract void gapClick();
}
2.实现ClickGapListener
btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new ClickGapListener() {
@Override
protected void gapClick() {
Toast.makeText(MainActivity.this,"点击事件",Toast.LENGTH_SHORT).show();
}
});
2.用AspectJ实现
使用AspectJ能够更加优雅的实现这个需求,且代码的侵入性更低。
2.1引入AspectJ
1.在项目的build.gradle当中加入引用
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.0'
2.在app的build.gradle当中加入plugin
apply plugin: 'android-aspectjx'
3.在app或者其他的模块当中加入依赖
implementation 'org.aspectj:aspectjrt:1.8.9'
2.2制作切面
1.增加ClickGap注解
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface ClickGap {
}
2.编写切面处理类
@Aspect
public class AspectUtil {
private static long clickGapTime = 0;
public static final int CLICK_GAP_RESPONSE = 500;//500ms内不响应
//判断是否应该执行,true执行,false不执行
protected boolean clickGapFilter(){
long currentTimeMillis = System.currentTimeMillis();
if(currentTimeMillis-clickGapTime< CLICK_GAP_RESPONSE){
return false;
}
clickGapTime = currentTimeMillis;
return true;
}
@Around("execution(@ClickGap * *(..))")
public void clickGap(ProceedingJoinPoint proceedingJoinPoint)throws Throwable {
if(clickGapFilter() == true) {
proceedingJoinPoint.proceed();
}
}
}
3.使用,直接在执行的点击函数上增加ClickGap注解即可
btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
@ClickGap
public void onClick(View view) {
Toast.makeText(MainActivity.this,"hello",Toast.LENGTH_SHORT).show();
}
});
3.总结
使用AspectJ处理这类事件可以使得代码逻辑很清晰,其他类似网络请求前判断是流量还是WiFi、日志打印前判断当前是release版本还是debug版本之类的需求都可以使用这种方法实现。
不过需要注意的是,在项目当中大量加入注解,会使得编译比较慢。