android防止按钮连续点击方案之AOP
转载请标明出处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的更多相关文章
- Android防止按钮连续点击
		
为了防止用户或者测试MM疯狂的点击某个button,写个方法防止按钮连续点击. public class Utils { private static long lastClickTime; publ ...
 - Android 防止按钮连续点击的方法(Button,ImageButton等)
		
防止按钮连续点击 其实实现很简单 共通方法 public class Utils { private static long lastClickTime; public static boolean ...
 - Runtime应用防止按钮连续点击 (转)
		
好久之前就看到过使用Runtime解决按钮的连续点击的问题,一直觉得没啥好记录的.刚好今天旁边同时碰到这个问题,看他们好捉急而且好像很难处理,于是我先自己看看… 前面自己也学习了很多Runtime的东 ...
 - Android通过AOP实现防止按钮连续点击
		
防止连续点击的实现方式有很多种,比如,在所有的onclick里面加上防多次点击的代码,或者定义一个新的OnClickListener,在里面加上防多次点击的代码,然后项目中的所有OnClickList ...
 - 【Android】按钮点击事件的常用写法
		
学习总结: 最近学习了Android点击事件的常用写法.点击事件会触发监听对象身上的回调,常用写法有以下四种: 方法一:使用匿名内部类. public class MainActivity exten ...
 - Android实现按钮点击效果(第一次点击变色,第二次恢复)
		
1.首先创建一个按钮 <Button android:id="@+id/click" android:layout_width="fill_parent" ...
 - Android Listview中Button按钮点击事件冲突解决办法
		
今天做项目时,ListView中含有了Button组件,心里一早就知道肯定会有冲突,因为以前就遇到过,并解决过,可惜当时没有记录下来. 今天在做的时候,继续被这个问题郁闷了一把,后来解决后,赶紧来记录 ...
 - 关于Android避免按钮重复点击事件
		
最近测试人员测试我们的APP的时候,喜欢快速点击某个按钮,出现一个页面出现多次,测试人员能不能禁止这样.我自己点击了几下,确实存在这个问题,也感觉用户体验不太好.于是乎后来我搜了下加一个方法放在我们U ...
 - android 自定义控件——(五)按钮点击变色
		
----------------------------------按钮点击变色(源代码下有属性解释)------------------------------------------------- ...
 
随机推荐
- 机器学习:分类算法性能指标之ROC曲线
			
在介绍ROC曲线之前,先说说混淆矩阵及两个公式,因为这是ROC曲线计算的基础. 1.混淆矩阵的例子(是否点击广告): 说明: TP:预测的结果跟实际结果一致,都点击了广告. FP:预测结果点击了,但是 ...
 - HDU 1251 统计难题 字符匹配
			
题目描述:先说明此题只有一个测试实例,然后输入一系列的单词,以一个回车为结束符,然后输入一个字符串,要你查找以这个字符串为前缀的单词的个数,处理到文件结束. 解题报告:一开始看到这题,竟然直接用暴力去 ...
 - 第9月第26天 pairs和ipairs cocos2dx 动画
			
1. a={ ip = "127.0.0.1", port = 6789 } for i,v in pairs(a) do print(i,v) end a={1} for i,v ...
 - Memcached命令:简单获取缓存value用法
			
Memcached:命令用法1.cmd 输入telnet ip 端口 进入memcached服务端窗口比如:xxx.Token_T1435622096xxx为key获取此key的memcached ...
 - HTTP协议之响应头Date与Age
			
HTTP没有为用户提供一种手段来区分响应是缓存命中的,还是访问原始服务器得到的.客户端有一种方法能判断响应是否来自缓存,就是使用Date首部.将响应中Date首部的值与当前时间进行比较,如果响应中的日 ...
 - rap 部署
			
Rap 安装 war包下载地址 https://github.com/thx/RAP/releases 创建数据库,并创建权限用户 mysql> create database rap_db c ...
 - python3转变exe的方法
			
python开发的代码可能在其他windows上并不能使用用,除非别人的环境中也有python. 下面是如何将python开发的东西转为exe格式 1.安装pyinstaller pip instal ...
 - VELT-0.1.5开发:使用kgdb调试Linux内核【转】
			
转自:http://demo.netfoucs.com/lights_joy/article/details/44106589 VELT的全称是Visual EmbedLinuxTools,它是一个与 ...
 - java Queue
			
队列是一个典型的先进先出(FIFO)的容器,即从容器的一端放入事物,从另一端取出,并且事物放入容器的顺序与取出的顺序是相同的,队列常常被当作一种可靠的对象从程序的某个区域传输到另一个区域,队列在并发编 ...
 - Java第三阶段学习(十二、HttpServletRequest与HttpServletResponse)
			
一.HttpServletRequest 1.概述: 我们在创建Servlet时会覆盖service()方法,或doGet()/doPost(),这些方法都有两个参数,一个为代表请求的request和 ...