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;
    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM