Android gère les clics de bouton répétés avec élégance
Traitement précédent
Les méthodes trouvées en ligne ou auxquelles vous pourriez penser sont probablement les suivantes:
1. Dans chaque événement de clic de bouton, enregistrez le temps de clic et évaluez s'il dépasse l'intervalle de temps de clic.
private long mLastClickTime = 0;
public static final long TIME_INTERVAL = 1000L;
private Button btTest;
private void initView() {
btTest = findViewById(R.id.bt_test);
btTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
long nowTime = System.currentTimeMillis();
if (nowTime - mLastClickTime > TIME_INTERVAL) {
// do something
mLastClickTime = nowTime;
} else {
Toast.makeText(MainActivity.this, "不要重复点击", Toast.LENGTH_SHORT).show();
}
}
});
}
De cette façon, chaque événement de clic doit écrire un jugement temporel et beaucoup de code répété.
2. Encapsulez un événement de clic pour gérer le jugement de l'intervalle de clic
public abstract class CustomClickListener implements View.OnClickListener {
private long mLastClickTime;
private long timeInterval = 1000L;
public CustomClickListener() {
}
public CustomClickListener(long interval) {
this.timeInterval = interval;
}
@Override
public void onClick(View v) {
long nowTime = System.currentTimeMillis();
if (nowTime - mLastClickTime > timeInterval) {
// 单次点击事件
onSingleClick();
mLastClickTime = nowTime;
} else {
// 快速点击事件
onFastClick();
}
}
protected abstract void onSingleClick();
protected abstract void onFastClick();
}
utilisation:
btTest.setOnClickListener(new CustomClickListener() {
@Override
protected void onSingleClick() {
Log.d("xxx", "onSingleClick");
}
@Override
protected void onFastClick() {
Log.d("xxx", "onFastClick");
}
});
Par rapport à la première méthode, cette méthode encapsule le jugement des clics répétés dans le CustomClickListener, et il n'est pas nécessaire de traiter le jugement de temps en externe, et seule la méthode de clic doit être implémentée.
3. Utilisez RxAndroid pour gérer les clics répétés
RxView.clicks(view)
.throttleFirst(1, TimeUnit.SECONDS)
.subscribe(new Consumer<Object>() {
@Override
public void accept(Object o) throws Exception {
// do something
}
});
Gérez de manière réactive les clics sur les boutons et utilisez les opérateurs rxjava pour éviter les clics répétés. Par rapport aux première et deuxième solutions, cette méthode est plus élégante.
réfléchissez un moment:
Ces trois méthodes, quelle que soit celle-ci, sont très intrusives pour l'événement de clic d'origine. Soit vous devez ajouter une méthode à l'événement Click, soit vous devez remplacer tout l'événement Click. Alors, existe-t-il un moyen? Sans changer le logique originale, comment gérer correctement les clics répétés de boutons?
Une approche plus élégante
Ajoutez une logique de traitement unifiée à toutes les méthodes du même type, et nous pouvons rapidement penser à un mot: AOP , oui, programmation orientée aspect.
Comment utiliser AOP pour résoudre le problème des clics répétés?
1. Présentez Aspectj
Utilisez la programmation AOP sur Android, utilisez généralement la bibliothèque Aspectj
Debout sur les épaules de géants, Hujiang a ouvert le plugin Gradle d'Aspectj, ce qui nous permet d'utiliser Aspectj
- Dans le build.gradle sous le répertoire racine du projet, ajoutez des dépendances:
dependencies {
......
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.0'
}
- Dans le build.gradle sous l'application ou un autre répertoire de module, ajoutez:
// 注意:主App中请确保添加aspectjx
apply plugin: 'android-aspectjx'
dependencies {
......
implementation 'org.aspectj:aspectjrt:1.8.9'
}
2. Ajoutez une annotation personnalisée
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SingleClick {
/* 点击间隔时间 */
long value() default 1000;
}
La raison de l'ajout d'annotations personnalisées est de faciliter la gestion des méthodes qui utilisent l'AOP des clics répétés, et en même temps, l'intervalle de temps de clic peut être passé dans les annotations, ce qui est plus flexible.
3. Encapsulez une classe d'outils de jugement de clic répété
public final class XClickUtil {
/**
* 最近一次点击的时间
*/
private static long mLastClickTime;
/**
* 最近一次点击的控件ID
*/
private static int mLastClickViewId;
/**
* 是否是快速点击
*
* @param v 点击的控件
* @param intervalMillis 时间间期(毫秒)
* @return true:是,false:不是
*/
public static boolean isFastDoubleClick(View v, long intervalMillis) {
int viewId = v.getId();
long time = System.currentTimeMillis();
long timeInterval = Math.abs(time - mLastClickTime);
if (timeInterval < intervalMillis && viewId == mLastClickViewId) {
return true;
} else {
mLastClickTime = time;
mLastClickViewId = viewId;
return false;
}
}
}
4. Classe de traitement Ecrire Aspect AOP
@Aspect
public class SingleClickAspect {
private static final long DEFAULT_TIME_INTERVAL = 5000;
/**
* 定义切点,标记切点为所有被@SingleClick注解的方法
* 注意:这里me.baron.test.annotation.SingleClick需要替换成
* 你自己项目中SingleClick这个类的全路径哦
*/
@Pointcut("execution(@me.baron.test.annotation.SingleClick * *(..))")
public void methodAnnotated() {}
/**
* 定义一个切面方法,包裹切点方法
*/
@Around("methodAnnotated()")
public void aroundJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable {
// 取出方法的参数
View view = null;
for (Object arg : joinPoint.getArgs()) {
if (arg instanceof View) {
view = (View) arg;
break;
}
}
if (view == null) {
return;
}
// 取出方法的注解
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
if (!method.isAnnotationPresent(SingleClick.class)) {
return;
}
SingleClick singleClick = method.getAnnotation(SingleClick.class);
// 判断是否快速点击
if (!XClickUtil.isFastDoubleClick(view, singleClick.value())) {
// 不是快速点击,执行原方法
joinPoint.proceed();
}
}
}
Instructions
private void initView() {
btTest = findViewById(R.id.bt_test);
btTest.setOnClickListener(new View.OnClickListener() {
// 如果需要自定义点击时间间隔,自行传入毫秒值即可
// @SingleClick(2000)
@SingleClick
@Override
public void onClick(View v) {
// do something
}
});
}
Une seule annotation est nécessaire pour éviter les clics répétés sur le bouton. Toutes les autres tâches sont transférées au compilateur. Le code est beaucoup actualisé.
--------------------------------------------
Présentation d'AspectJ
L'introduction d'Eclipse et d'Android Studio est différente. Cet article présente uniquement comment Android Studio présente AspectJ. Veuillez Baidu pour Eclipse. Android Studio doit être introduit dans le fichier build.gradle du module d'application, qui est divisé en 3 étapes:
1) Ajouter des dépendances principales
dependencies {
...
compile 'org.aspectj:aspectjrt:1.8.9'
}
2) Ecrire le script de compilation gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.aspectj:aspectjtools:1.8.9'
classpath 'org.aspectj:aspectjweaver:1.8.9'
}
}