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

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

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

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

使用OnClickLitener的代码

public class MainActivity extends AppCompatActivity {
final String TAG = MainActivity.class.getSimpleName(); @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.text).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e(TAG, "execute click");
}
});
}
}

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

public class NoDoubleClickUtils {
private static long lastClickTime = 0;
private final static int SPACE_TIME = 500; public synchronized static boolean isDoubleClick() {
long currentTime = System.currentTimeMillis();
boolean isClick2;
if (currentTime - lastClickTime >
SPACE_TIME) {
isClick2 = false;
} else {
isClick2 = true;
}
lastClickTime = currentTime;
return isClick2;
}
}

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

@Aspect
public class AspectTest {
final String TAG = AspectTest.class.getSimpleName(); @Around("execution(* android.view.View.OnClickListener.onClick(..))")
public void onClickLitener(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Log.e(TAG, "OnClick");
if (!NoDoubleClickUtils.isDoubleClick()) {
proceedingJoinPoint.proceed();
}
}
}

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

04-03 19:41:20.043 5784-5784/ E/AspectTest: OnClick
04-03 19:41:20.043 5784-5784/ E/MainActivity: execute click
04-03 19:41:20.222 5784-5784/ E/AspectTest: OnClick
04-03 19:41:20.377 5784-5784/ E/AspectTest: OnClick
04-03 19:41:20.542 5784-5784/ E/AspectTest: OnClick
04-03 19:41:20.689 5784-5784/ E/AspectTest: OnClick
04-03 19:41:20.838 5784-5784/ E/AspectTest: OnClick
04-03 19:41:21.012 5784-5784/ E/AspectTest: OnClick
04-03 19:41:21.158 5784-5784/ E/AspectTest: OnClick

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

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

首先定义个注解

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

并且修改之前的AspectTest文件

	private boolean canDoubleClick = false;
private View mLastView; @Before("@annotation(com.kun.aspectjtest.aspect.DoubleClick)")
public void beforeEnableDoubleClcik(JoinPoint joinPoint) throws Throwable {
canDoubleClick = true;
} @Around("execution(* android.view.View.OnClickListener.onClick(..)) && target(Object) && this(Object)")
public void OnClickListener(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] objects = joinPoint.getArgs();
View view = objects.length == 0 ? null : (View) objects[0];
Log.e(TAG, "OnClick:" + view);
if (view != mLastView || canDoubleClick || !NoDoubleClickUtils.isDoubleClick()) {
joinPoint.proceed();
canDoubleClick = false;
}
mLastView = view;
}

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

public class MainActivity extends AppCompatActivity {
final String TAG = MainActivity.class.getSimpleName(); @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.text).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e(TAG, "text execute click");
}
}); findViewById(R.id.text2).setOnClickListener(new View.OnClickListener() {
@DoubleClick
@Override
public void onClick(View v) {
Log.e(TAG, "text2 execute click");
}
});
}
}

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

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}
04-03 23:18:25.598 2965-2965/ E/MainActivity: text execute click
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}
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}
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}
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}
04-03 23:18:29.473 2965-2965/ E/MainActivity: text2 execute click
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}
04-03 23:18:29.644 2965-2965/ E/MainActivity: text2 execute click
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}
04-03 23:18:29.801 2965-2965/ E/MainActivity: text2 execute click
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}
04-03 23:18:29.965 2965-2965/ E/MainActivity: text2 execute click

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

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

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

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

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

代码如下:

    private boolean canDoubleClick = false;

    @Around("@annotation(com.kun.aspectjtest.aspect.DoubleClick)")
public void beforeEnableDoubleClcik(JoinPoint joinPoint) throws Throwable {
canDoubleClick = true;
} private View mLastView; @Around("(execution(* android.view.View.OnClickListener.onClick(..))||execution(* butterknife.internal.DebouncingOnClickListener.doClick(..))) && target(Object) && this(Object)")
public void OnClickListener(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] objects = joinPoint.getArgs();
View view = objects.length == 0 ? null : (View) objects[0];
Log.e(TAG, "OnClick:" + view);
if (view != mLastView || canDoubleClick || !NoDoubleClickUtils.isDoubleClick()) {
joinPoint.proceed();
canDoubleClick = false;
}
mLastView = view;
}

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 自定义控件——(五)按钮点击变色

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

  5. android防止按钮连续点击方案之AOP

    转载请标明出处http://www.cnblogs.com/yxx123/p/6675567.html 防止连续点击的实现方式有很多种,比如,在所有的onclick里面加上防多次点击的代码,或者定义一 ...

  6. Android 四种方法写按钮点击事件

    1.匿名内部类的方式 2. 创建一个类实现onclickListener,实现onclick方法,设置控件点击事件时传一个类的对象. 3. 让当前类实现onclickListener,设置控件点击事件 ...

  7. Android 如何通过代码模拟按钮点击 延时函数

    View.performClick();   比如: private Button mButton01;    mButton01 = (Button)findViewById(R.id.myButt ...

  8. Android下实现win8的按钮点击效果

    原理就是自定义一个imageButton,实现动画效果 demo源码下载地址:  请戳这里----------------> 关于回弹张力的效果扩展,可以参考Facebook的开源动画库rebo ...

  9. android 按钮点击效果实现

    在其他人的博客里看到其实实现按钮点击效果的方法有很多,这里提到的只是其中一个办法 图片素材(我自己用截图截的,可以自己搞) 放到mipmap目录下(studio是在这个目录下 , eclipse 直接 ...

随机推荐

  1. BZOJ 3083: 遥远的国度(树链剖分+DFS序)

    可以很显而易见的看出,修改就是树链剖分,而询问就是在dfs出的线段树里查询最小值,但由于这道题会修改根节点,所以在查询的时候需判断x是否为root的祖先,如果不是就直接做,是的话应该查询从1-st[y ...

  2. unity脚本的运行顺序以及单例的实现

    unity引擎把所有脚本先行编译后,在运行的时候一批,一批的函数进行执行. unity脚本自带函数执行顺序如下:将下面脚本挂在任意物体运行即可得到 Awake ->OnEable-> St ...

  3. nodemailer中的几个坑

    nodemailer是什么 nodemailer是一个nodejs的邮件服务模块 如何用nodemailer发邮件 1.先安装nodemailer npm i --save nodemailer 2. ...

  4. MSSQL数据批量插入优化详细

    序言 现在有一个需求是将10w条数据插入到MSSQL数据库中,表结构如下,你会怎么做,你感觉插入10W条数据插入到MSSQL如下的表中需要多久呢? 或者你的批量数据是如何插入的呢?我今天就此问题做个探 ...

  5. SaberRD之蒙特卡罗分析(一)

    [声明]本博文的大部分内容摘录于网络,本人按照自己的思维习惯和文字风格进行了重新整理以便于理解和记忆. 鉴于篇幅,我打算先对蒙特卡罗分析的基本思想和历史渊源做一下简单的梳理,然后在下一篇博文中介绍Sa ...

  6. Mac上写C++

    用惯Windows的同学可能刚开始用Mac的时候并不知道如何写C++,我刚开始在Mac上写C++的时候也遇到过这个困扰,Mac上并没有Windows上自己用习惯的Visual C++,下面我分享一下个 ...

  7. Linux TCP连接数修改

    一.           文件数限制修改 (1)   vi /etc/security/limits.conf *  soft nofile 10240    *  hard nofile 10240 ...

  8. 一个chrome图片下载插件的开发过程

    最近在做采集,发现用chrome的插件来下载整站也是一个不错的思路,所以想开发一个下载网页(仿站)的插件,学习过程如下: 首先查看一些文档资料 学习360翻译的开发文档:http://open.se. ...

  9. KEEP!

    [list][*]别问我前端有没有前途,我不知道,我只知道我现在喜欢前端,以后也应该喜欢.[*]别问我前端的工作好不好找,不管哪一职位,工作好不好找都是看你的水平.[*]别问我前端累不累,这世界就没有 ...

  10. WEB标准了解

    今天看到朋友的简历有一项“了解WEB标准”,就特地了解了一下什么是WEB标准.现在就一项一项地解开自己的疑惑. 1.什么是WEB标准 WEB标准大部分由万维网组织(W3C)制定的WEB程序开发规范.W ...