转载请标明出处http://www.cnblogs.com/yxx123/p/6675567.html

防止连续点击的实现方式有很多种,比如,在所有的onclick里面加上防多次点击的代码,或者定义一个新的OnClickListener,在里面加上防多次点击的代码,然后项目中的所有OnClickListener都用这个listener,当然还有一些其他的方式,这里将介绍一种新的方式来实现,那就是aop。

不知道aop的可以看这篇文章深入理解Android之AOP

在android实现aop通常是用AspectJ来实现,AspectJ的用法可以看这篇文章AspectJ基本用法.

使用OnClickLitener的代码

  1. public class MainActivity extends AppCompatActivity {
  2. final String TAG = MainActivity.class.getSimpleName();
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_main);
  7. findViewById(R.id.text).setOnClickListener(new View.OnClickListener() {
  8. @Override
  9. public void onClick(View v) {
  10. Log.e(TAG, "execute click");
  11. }
  12. });
  13. }
  14. }

首先定义一个防止多次点击的工具类

  1. public class NoDoubleClickUtils {
  2. private static long lastClickTime = 0;
  3. private final static int SPACE_TIME = 500;
  4. public synchronized static boolean isDoubleClick() {
  5. long currentTime = System.currentTimeMillis();
  6. boolean isClick2;
  7. if (currentTime - lastClickTime >
  8. SPACE_TIME) {
  9. isClick2 = false;
  10. } else {
  11. isClick2 = true;
  12. }
  13. lastClickTime = currentTime;
  14. return isClick2;
  15. }
  16. }

然后使用AspectJ对OnclickLitener进行插桩,

  1. @Aspect
  2. public class AspectTest {
  3. final String TAG = AspectTest.class.getSimpleName();
  4. @Around("execution(* android.view.View.OnClickListener.onClick(..))")
  5. public void onClickLitener(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
  6. Log.e(TAG, "OnClick");
  7. if (!NoDoubleClickUtils.isDoubleClick()) {
  8. proceedingJoinPoint.proceed();
  9. }
  10. }
  11. }

运行程序,多次点击按钮后,log如下

  1. 04-03 19:41:20.043 5784-5784/ E/AspectTest: OnClick
  2. 04-03 19:41:20.043 5784-5784/ E/MainActivity: execute click
  3. 04-03 19:41:20.222 5784-5784/ E/AspectTest: OnClick
  4. 04-03 19:41:20.377 5784-5784/ E/AspectTest: OnClick
  5. 04-03 19:41:20.542 5784-5784/ E/AspectTest: OnClick
  6. 04-03 19:41:20.689 5784-5784/ E/AspectTest: OnClick
  7. 04-03 19:41:20.838 5784-5784/ E/AspectTest: OnClick
  8. 04-03 19:41:21.012 5784-5784/ E/AspectTest: OnClick
  9. 04-03 19:41:21.158 5784-5784/ E/AspectTest: OnClick

通过log可以看出onClickLitener执行了多次,但使用clcik的的地方只执行了一次。这样,就可以在不改变原来代码的情况下,实现防止连续点击的功能。

但是当又有需求:要求部分按钮是可以连续点击的,该怎么办能?这个时候只要加个注解文件就好。

首先定义个注解

  1. @Retention(RetentionPolicy.CLASS)
  2. @Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
  3. public @interface DoubleClick {
  4. }

并且修改之前的AspectTest文件

  1. private boolean canDoubleClick = false;
  2. private View mLastView;
  3. @Before("@annotation(com.kun.aspectjtest.aspect.DoubleClick)")
  4. public void beforeEnableDoubleClcik(JoinPoint joinPoint) throws Throwable {
  5. canDoubleClick = true;
  6. }
  7. @Around("execution(* android.view.View.OnClickListener.onClick(..)) && target(Object) && this(Object)")
  8. public void OnClickListener(ProceedingJoinPoint joinPoint) throws Throwable {
  9. Object[] objects = joinPoint.getArgs();
  10. View view = objects.length == 0 ? null : (View) objects[0];
  11. Log.e(TAG, "OnClick:" + view);
  12. if (view != mLastView || canDoubleClick || !NoDoubleClickUtils.isDoubleClick()) {
  13. joinPoint.proceed();
  14. canDoubleClick = false;
  15. }
  16. mLastView = view;
  17. }

现在只要在可以连续点击的按钮的onclick前加一个@DoubleClick的注解就好,将MainActivty修改如下

  1. public class MainActivity extends AppCompatActivity {
  2. final String TAG = MainActivity.class.getSimpleName();
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_main);
  7. findViewById(R.id.text).setOnClickListener(new View.OnClickListener() {
  8. @Override
  9. public void onClick(View v) {
  10. Log.e(TAG, "text execute click");
  11. }
  12. });
  13. findViewById(R.id.text2).setOnClickListener(new View.OnClickListener() {
  14. @DoubleClick
  15. @Override
  16. public void onClick(View v) {
  17. Log.e(TAG, "text2 execute click");
  18. }
  19. });
  20. }
  21. }

运行程序,分别连续点击第一个view和第二个view,log如下

  1. 04-03 23:18:25.598 2965-2965/ E/AspectTest: OnClick:AppCompatTextView{967c04b V.ED..C.. ...P.... 427,579-652,636 #7f0b005d app:id/text}
  2. 04-03 23:18:25.598 2965-2965/ E/MainActivity: text execute click
  3. 04-03 23:18:25.768 2965-2965/ E/AspectTest: OnClick:AppCompatTextView{967c04b V.ED..C.. ...P.... 427,579-652,636 #7f0b005d app:id/text}
  4. 04-03 23:18:25.941 2965-2965/ E/AspectTest: OnClick:AppCompatTextView{967c04b V.ED..C.. ...P.... 427,579-652,636 #7f0b005d app:id/text}
  5. 04-03 23:18:26.113 2965-2965/ E/AspectTest: OnClick:AppCompatTextView{967c04b V.ED..C.. ...P.... 427,579-652,636 #7f0b005d app:id/text}
  6. 04-03 23:18:29.473 2965-2965/ E/AspectTest: OnClick:AppCompatTextView{2c5ea28 V.ED..C.. ...P.... 427,936-652,993 #7f0b005e app:id/text2}
  7. 04-03 23:18:29.473 2965-2965/ E/MainActivity: text2 execute click
  8. 04-03 23:18:29.644 2965-2965/ E/AspectTest: OnClick:AppCompatTextView{2c5ea28 V.ED..C.. ...P.... 427,936-652,993 #7f0b005e app:id/text2}
  9. 04-03 23:18:29.644 2965-2965/ E/MainActivity: text2 execute click
  10. 04-03 23:18:29.801 2965-2965/ E/AspectTest: OnClick:AppCompatTextView{2c5ea28 V.ED..C.. ...P.... 427,936-652,993 #7f0b005e app:id/text2}
  11. 04-03 23:18:29.801 2965-2965/ E/MainActivity: text2 execute click
  12. 04-03 23:18:29.965 2965-2965/ E/AspectTest: OnClick:AppCompatTextView{2c5ea28 V.ED..C.. ...P.... 427,936-652,993 #7f0b005e app:id/text2}
  13. 04-03 23:18:29.965 2965-2965/ E/MainActivity: text2 execute click

可以发现第一个view不能被连续点击了,但第二个可以连续点击。

如果项目里用了butterknife,需要修改execution语句,改为

  1. (execution(* android.view.View.OnClickListener.onClick(..))||execution(* butterknife.internal.DebouncingOnClickListener.doClick(..))) && target(Object) && this(Object)

并且在build.gradle文件中加入过滤

  1. aspectjx {
  2. includeJarFilter 'butterknife'//织入遍历butterknife
  3. excludeJarFilter '.jar'//忽略所有依赖的库
  4. }

代码如下:

  1. private boolean canDoubleClick = false;
  2. @Around("@annotation(com.kun.aspectjtest.aspect.DoubleClick)")
  3. public void beforeEnableDoubleClcik(JoinPoint joinPoint) throws Throwable {
  4. canDoubleClick = true;
  5. }
  6. private View mLastView;
  7. @Around("(execution(* android.view.View.OnClickListener.onClick(..))||execution(* butterknife.internal.DebouncingOnClickListener.doClick(..))) && target(Object) && this(Object)")
  8. public void OnClickListener(ProceedingJoinPoint joinPoint) throws Throwable {
  9. Object[] objects = joinPoint.getArgs();
  10. View view = objects.length == 0 ? null : (View) objects[0];
  11. Log.e(TAG, "OnClick:" + view);
  12. if (view != mLastView || canDoubleClick || !NoDoubleClickUtils.isDoubleClick()) {
  13. joinPoint.proceed();
  14. canDoubleClick = false;
  15. }
  16. mLastView = view;
  17. }

android防止按钮连续点击方案之AOP的更多相关文章

  1. Android防止按钮连续点击

    为了防止用户或者测试MM疯狂的点击某个button,写个方法防止按钮连续点击. public class Utils { private static long lastClickTime; publ ...

  2. Android 防止按钮连续点击的方法(Button,ImageButton等)

    防止按钮连续点击  其实实现很简单 共通方法 public class Utils { private static long lastClickTime; public static boolean ...

  3. Runtime应用防止按钮连续点击 (转)

    好久之前就看到过使用Runtime解决按钮的连续点击的问题,一直觉得没啥好记录的.刚好今天旁边同时碰到这个问题,看他们好捉急而且好像很难处理,于是我先自己看看… 前面自己也学习了很多Runtime的东 ...

  4. Android通过AOP实现防止按钮连续点击

    防止连续点击的实现方式有很多种,比如,在所有的onclick里面加上防多次点击的代码,或者定义一个新的OnClickListener,在里面加上防多次点击的代码,然后项目中的所有OnClickList ...

  5. 【Android】按钮点击事件的常用写法

    学习总结: 最近学习了Android点击事件的常用写法.点击事件会触发监听对象身上的回调,常用写法有以下四种: 方法一:使用匿名内部类. public class MainActivity exten ...

  6. Android实现按钮点击效果(第一次点击变色,第二次恢复)

    1.首先创建一个按钮 <Button android:id="@+id/click" android:layout_width="fill_parent" ...

  7. Android Listview中Button按钮点击事件冲突解决办法

    今天做项目时,ListView中含有了Button组件,心里一早就知道肯定会有冲突,因为以前就遇到过,并解决过,可惜当时没有记录下来. 今天在做的时候,继续被这个问题郁闷了一把,后来解决后,赶紧来记录 ...

  8. 关于Android避免按钮重复点击事件

    最近测试人员测试我们的APP的时候,喜欢快速点击某个按钮,出现一个页面出现多次,测试人员能不能禁止这样.我自己点击了几下,确实存在这个问题,也感觉用户体验不太好.于是乎后来我搜了下加一个方法放在我们U ...

  9. android 自定义控件——(五)按钮点击变色

    ----------------------------------按钮点击变色(源代码下有属性解释)------------------------------------------------- ...

随机推荐

  1. [转载]五理由 .NET开发者应该关注HTML 5

    http://developer.51cto.com/art/201107/275039.htm

  2. jQuery中Animate进阶用法(三)

    progressType: Function( Promise animation, Number progress, Number remainingMs )每一步动画完成后调用的一个函数,无论动画 ...

  3. Windows::Docker::Ubuntu 做 SLAM

    如题,这是一件很蛋疼的事情. 为了完成这一件事情,需要达成目标: Ubuntu GUI 必须要能够显示. Ubuntu 可以链接 USB Camera. 目标一 目标1很容易达成. 在 Win10 中 ...

  4. linux内存管理-内核用户空间 【转】

    转自:http://blog.chinaunix.net/uid-25909619-id-4491362.html 1,linux内存管理中几个重要的结构体和数组 page unsigned long ...

  5. linux下热插拔事件的产生是怎样通知到用户空间,kobject_uevent_env之uevent【转】

    转自:http://blog.csdn.net/myarrow/article/details/8259888 1.kobject, ktype, kset 1) kobject: 代表sysfs中的 ...

  6. mitmproxy实践

    首先附上github地址:https://github.com/mitmproxy/mitmprox,上面的内容永远是最新的 作为一名测试穿戴设备相关app的工程师,与数据打交道是常事,那么,如果想要 ...

  7. 发布构件到Maven中央仓库

    一.注册jira账号 访问如下网址: https://issues.sonatype.org/secure/Signup.jspa 记住邮箱,用户名,密码以备以后使用,一定牢记. 二.创建一个issu ...

  8. mybatis,genarate自动生成代码

    ---恢复内容开始--- generatorConfig.xml配置文件: <?xml version="1.0" encoding="UTF-8"?&g ...

  9. CMD命令行下修改网络IP设置的方法

    1.全自动修改网络地址: 复制代码 代码如下: @echo off netsh interface ip set address name="本地连接" static 192.16 ...

  10. 2016 版 Laravel 系列入门教程

    2016 版 Laravel 系列入门教程 (1) - (5) http://www.golaravel.com/post/2016-ban-laravel-xi-lie-ru-men-jiao-ch ...