欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android中如何优雅的处理重复点击实例代码

程序员文章站 2022-06-19 19:47:48
问题 有时候有些操作是防止用户在一次响应结束中再响应下一个。但有些测试用户就要猛点,狂点。像这种恶意就要进行防止。 比如在客户端中,一些按钮一般是需要避免重复点击的...

问题

有时候有些操作是防止用户在一次响应结束中再响应下一个。但有些测试用户就要猛点,狂点。像这种恶意就要进行防止。

比如在客户端中,一些按钮一般是需要避免重复点击的,比如:购买丶支付丶确定丶提交丶点赞丶收藏等等场景,这些场景短时间内的重复点击会引发一些问题.

下面话不多说了,来一起看看详细的介绍吧

以前的处理方式

可能是采用手动记录最后的点击时间,再通过计算时间间隔来判断是否重复点击

 private long mlastclicktime = 0;
 public static final int time_interval = 1000;
 private button mbutton;

 private void initview() {
 mbutton.setonclicklistener(new view.onclicklistener() {
  @override
  public void onclick(view v) {
  if (system.currenttimemillis() - mlastclicktime >= time_interval) {
   //to do
   mlastclicktime = system.currenttimemillis();
  } else {
   toast.maketext(getactivity(), "请勿重复点击", toast.length_long).show();
  }
  }
 });
 }

或者封装一下采用抽象处理

public abstract class iclicklistener implements view.onclicklistener {
 private long mlastclicktime = 0;
 public static final int time_interval = 1000;

 @override
 public final void onclick(view v) {
 if (system.currenttimemillis() - mlastclicktime >= time_interval) {
  oniclick(v);
  mlastclicktime = system.currenttimemillis();
 } else {
  onagain(v);
 }
 }

 protected abstract void oniclick(view v);

 protected void onagain(view v) {

 }
}

使用(无需提醒重复点击)

 mbutton.setonclicklistener(new iclicklistener() {
  @override
  protected void oniclick(view v) {
  
  }
 });

或者(需提醒重复点击)

        mbutton.setonclicklistener(new iclicklistener() {
            @override
            protected void oniclick(view v) {
               
            }

            @override
            protected void onagain(view v) {

            }
        });
可以看到经过封装之后,使用起来还是很方便的,但是有几个缺点

  • 侵入性过大-onclicklistener全部替换为子类iclicklistener
  • 不可逆-不能很方便的还原为onclicklistener,因为不是同个回调
  • 如果是第三方控件则无法处理重复点击
  • 只能写成内部类方式-由于单继承特性,我们只能内部类回调,代码不美观

优雅的处理方式

重复点击的问题其实是如何动态控制原有的点击事件是否产生,而不是在原有的点击事件上增强功能;结合设计模式可以知道,代理模式可以很好的处理这种问题,而不是继承.

代理

public class clickproxy implements view.onclicklistener {

 private view.onclicklistener origin;
 private long lastclick = 0;
 private long timems = 1000;

 public clickproxy(view.onclicklistener origin) {
  this.origin = origin;
 }

 @override
 public void onclick(view v) {
  if (system.currenttimemillis() - lastclick >= timems) {
   origin.onclick(v);
   lastclick = system.currenttimemillis();
  }
 }
}

原先的点击事件

  mbutton.setonclicklistener(new view.onclicklistener() {
   @override
   public void onclick(view v) {
    //to do
   }
  });

代理使用

  mbutton.setonclicklistener(new clickproxy(new view.onclicklistener() {
   @override
   public void onclick(view v) {
    //to do
   }
  }));

可以看到,原有代码逻辑没有改动,只是添加了代理类,这样大大减小了侵入性

当然还可以扩展一下,提供重复点击的回调和自定义间隔时间,增加一个构造函数

public class clickproxy implements view.onclicklistener {

 private view.onclicklistener origin;
 private long lastclick = 0;
 private long timems = 1000; //ms
 private iagain miagain;

 public clickproxy(view.onclicklistener origin, long timems, iagain again) {
  this.origin = origin;
  this.miagain = again;
  this.timems = timems;
 }

 public clickproxy(view.onclicklistener origin) {
  this.origin = origin;
 }

 @override
 public void onclick(view v) {
  if (system.currenttimemillis() - lastclick >= timems) {
   origin.onclick(v);
   lastclick = system.currenttimemillis();
  } else {
   if (miagain != null) miagain.onagain();
  }
 }

 public interface iagain {
  void onagain();//重复点击
 }
}

如何处理第三方view内部的点击事件

可能我们使用一个自定义控件,他的内部已经消费了点击事件,但是需要避免重复点击,我们不可能去改内部的代码,也不能重新设置点击事件,那样会丢失内部的处理逻辑;这时可以采用反射的处理方式,再结合代理来实现无缝替换

//提供一个静态方法
public class clickfilter {
 public static void setfilter(view view) {
  try {
   field field = view.class.getdeclaredfield("mlistenerinfo");
   field.setaccessible(true);
   class listinfotype = field.gettype();
   object listinfo = field.get(view);
   field onclickfield = listinfotype.getfield("monclicklistener");
   view.onclicklistener origin = (view.onclicklistener) onclickfield.get(listinfo);
   onclickfield.set(listinfo, new clickproxy(origin));
  } catch (exception e) {
   e.printstacktrace();
  }
 }
}

使用:

 private statebutton mstatebutton;//自定义控件

 private void initview() {
  clickfilter.setfilter(mstatebutton);
 }

这种动态替换的方式同样适合普通场景,在设置点击事件后,都可以通过设置该过滤器来处理重复点击(包括butterknife等注解绑定的点击事件)

最后

ok.以上就是讨论如何优雅处理重复点击的全部内容,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。