防止按钮重复点击

2016-11-16  本文已影响0人  红烧排骨饭

防止按钮重复点击

按钮的 OnClick 事件是 Android 开发中最常见的事件,比如 Button 常常和 OnClickListener 绑定在一起,当 OnClick 事件发生时,就会回掉 OnClickListeneronClick(View) 方法,比如

findViewById(R.id.button_id).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // ...
    }
});

我们会在 onClick(View) 方法中做一些操作,比如在登陆按钮点击之后就会执行登陆操作,下订单按钮点击之后就会执行下单操作。

但是有个细节我们常常忽略,如果用户很短的时间内快速地对按钮点击多次,这样会造成 onClick(View) 方法被执行多次,就会造成重复登陆和重复下单的问题。这个问题有时候会造成一些错误的后果,在开发的过程中需要避免这样的问题发生。针对这种问题,有几种方法可以实现

标志位

比如一个登陆按钮,在 onClick(View) 方法体中,先判断标志位是否为 true,如果为 true 说明业务逻辑正在执行,就直接 return,否则就执行业务逻辑。当业务逻辑执行完毕之后再将标志位复位

private boolean mLoging;

private void initView() {
    findViewById(R.id.button_id).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (mLoading) {
                return;
            }
            
            login();
        }            
    });
}

private void login() {
    ApiWrapper.login(account, password, new CallBack() {
        
        @Override
        public void onSuccess() {
            // ...
            mLoading = false;
        }

        @Override
        public void onFailure() {
            // ...
            mLoading = false;
        }
    })
}

采用 标志位 这样的方法挺好的,就是需要额外维护一个标志位。一个按钮还好,如果按钮多了话,就需要维护多个标志位,有时候还容易忘了将标志位复位。

重写OnClickListener——标志位法

public abstract class NoClickQuicklyListener implements View.OnClickListener {

    private boolean mClickable = true;

    @Override
    public void onClick(View v) {
        if (mClickable) {
            mClickable = false;
            onClick();
        }
    }
    
    public void reset() {
        mClickable = true;
    }

    public abstract void onClick();
}

把标志位封装进 NoClickQuicklyListener 类中。不过感觉也不是很方便的样子,只是比第一种写法少了一点代码。

重写OnClickListener——时间间隔法

自定义一个类 NoClickQuicklyListener 实现 OnClickListener 接口。在类中维护一个记录时间的变量 lastClickTime,如果这一次点击事件发生的时间和上一次点击事件发生的时间的间隔太短,少于 MIN_CLICK_OFFSET_TIME 定义的时间间隔,就不执行业务逻辑

public abstract class NoClickQuicklyListener implements View.OnClickListener {

    private static final int MIN_CLICK_OFFSET_TIME = 1000;
    private long lastClickTime = 0;

    @Override
    public void onClick(View v) {
        long currentTimeMillis = System.currentTimeMillis();

        if (currentTimeMillis - lastClickTime > MIN_CLICK_OFFSET_TIME) {
            lastClickTime = currentTimeMillis;
            onClick();
        }
    }

    public abstract void onClick();
}

使用的时候,使用 NoClickQuicklyListener 代替 OnClickListener

findViewById(R.id.simple_button_id).setOnClickListener(new NoClickQuicklyListener() {
    @Override
    public void onClick() {
        // ...
    }
});

用这样的实现,就不需要维护额外的标志位了,代码少了很多,逻辑也会简单点。

使用RxJava的throttleFirst操作符

throttleFirst 操作符只允许在一定时间间隔类的第一个事件发出,对于其他事件则屏蔽。在到达时间间隔之后,再发出下一个事件。宝石图如下

throttleFirst.png

可以使用 RxView 配合 throttleFirst 操作符来实现

RxView.clicks(button)
        .throttleFirst(2000, TimeUnit.SECONDS)  // 时间间隔设置为2秒
        .subscribe(new Action1<Void>() {
            @Override
            public void call(Void aVoid) {
                // ...
            }
        });
上一篇下一篇

猜你喜欢

热点阅读