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 自定义控件——(五)按钮点击变色
----------------------------------按钮点击变色(源代码下有属性解释)------------------------------------------------- ...
- android防止按钮连续点击方案之AOP
转载请标明出处http://www.cnblogs.com/yxx123/p/6675567.html 防止连续点击的实现方式有很多种,比如,在所有的onclick里面加上防多次点击的代码,或者定义一 ...
- Android 四种方法写按钮点击事件
1.匿名内部类的方式 2. 创建一个类实现onclickListener,实现onclick方法,设置控件点击事件时传一个类的对象. 3. 让当前类实现onclickListener,设置控件点击事件 ...
- Android 如何通过代码模拟按钮点击 延时函数
View.performClick(); 比如: private Button mButton01; mButton01 = (Button)findViewById(R.id.myButt ...
- Android下实现win8的按钮点击效果
原理就是自定义一个imageButton,实现动画效果 demo源码下载地址: 请戳这里----------------> 关于回弹张力的效果扩展,可以参考Facebook的开源动画库rebo ...
- android 按钮点击效果实现
在其他人的博客里看到其实实现按钮点击效果的方法有很多,这里提到的只是其中一个办法 图片素材(我自己用截图截的,可以自己搞) 放到mipmap目录下(studio是在这个目录下 , eclipse 直接 ...
随机推荐
- Brackets 前端编辑器试用
Brackets编辑器介绍 "一个现代的,开源的,了解网页设计的编辑器"这是官方的宣传语.也就是说它适用于网页开发,包含了许多亮点功能:实时预览(Live Preview).内联编 ...
- [编织消息框架][设计协议]bit基础
理论部分 1字节等于8比特,也就是8个二进数,如下面公式 1Byte = 8bits = 0111 1111 1Short = 2Btye 1Int = 4Byte 那学这些有什么用呢? 可以用来做数 ...
- 网站Web业务架构从小到大演变
有一天,我突发奇想创建了一个站点,基于 LNMP 架构,起初只有我自己访问,后来因为我点儿正,访问量越来越大,所以最终导致下面的架构演变. 1.单台机器 单台机器因为只是一个小站,访问量一天也没有多少 ...
- 业务逻辑 : forex & mlm
业务逻辑 公司通过mlm的制度和顾客进行签约来收取资金,再把资金给第三方公司进行投资,再把所投资的回报给分配给公司和顾客. 公司的资金来自投资者,公司的营销策略来自mlm的制度,由市场人员来创建mlm ...
- 咖啡师之路:第一日一杯Espresso
代码敲累了.产品要发布了.熬夜啊加班啊. 精神完全不在状态. 咋办--- 咋办--- 咋办---! 来一杯Espresso浓缩咖啡.各位码农,码神们的必备良品! 咖啡每天要2-3杯,不管是速溶还是现磨 ...
- JSP中列表展示,隔行变色以及S标签的使用
1.java代码 /** * 列表展示,隔行变色以及S标签的使用 * * @return */ public String list() { List<User> list = new A ...
- KoaHub平台基于Node.js开发的Koa的模板系统handlebars插件代码详情
koahub-handlebars koahub-handlebars koahub handlebars templates Installation $ npm install koahub-ha ...
- Servlet 学习简介
一.Servlet简介 Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的 ...
- Spring Boot启动过程(五):Springboot内嵌Tomcat对象的start
标题和上一篇很像,所以特别强调一下,这个是Tomcat对象的. 从TomcatEmbeddedServletContainer的this.tomcat.start()开始,主要是利用Lifecycle ...
- 【树莓派】Linux应用相关:自动删除n天前日志
linux是一个很能自动产生文件的系统,日志.邮件.备份等.虽然现在硬盘廉价,我们可以有很多硬盘空间供这些文件浪费,让系统定时清理一些不需要的文件很有一种爽快的事情.不用你去每天惦记着是否需要清理日志 ...