zoukankan      html  css  js  c++  java
  • 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;
        }
    
  • 相关阅读:
    firefox native extension -- har export trigger
    配置jenkins slave 问题,ERROR: Couldn't find any revision to build. Verify the repository and branch configuration for this job.
    尝试用selenium+appium运行一个简单的demo报错:could not get xcode version. /Library/Developer/Info.plist doest not exist on disk
    ruby 除法运算
    ERB预处理ruby代码
    ruby self.included用法
    ruby include和exclude区别
    symfony安装使用
    解决git中文乱码
    读《微软的软件测试之道》有感(上)
  • 原文地址:https://www.cnblogs.com/yxx123/p/6675567.html
Copyright © 2011-2022 走看看