Android判断是否快速点击新思路


背景需求

在用户提交表单内容,请求接口的通用场景下,增删改查 crud 操作是比较频繁出现的操作。
对于改查操作来讲,并不会引起数据上的问题,影响的最多是接口重复调用;但是对于增删操作来讲,很容易引起数据重复添加,删除异常等问题。
对用户来讲,网络延时或者不稳定造成请求接口时出现的App反应迟缓,下意识的会进行重复提交;或者用户不小心进行的重复点击;又或者测试App自动化测试工具导致的短时间内大量重复点击。
这些场景都应该在代码实现的时候应该考虑的。

1. “笨”方法实现

说是笨方法,当然也是出现重复提交问题时候,想到的最有效的方法。

1.1 状态标记

对于每个点击按钮,初始状态 isPressed = FALSE 进行状态判定,点击一次记录状态 isPressed = TURE ,然后进行接口请求或者其它处理,接口请求完成之后初始化该按钮状态 isPressed = FALSE

1.2 状态标记高级版

Android 中怎样设置按钮不能点击?

其实,和上面的方法没什么区别,只不过借助了** Button **的属性设置来完成的。

Button.setEnabled(false);//设置这个属性

思路和1.1一致,生了一个局部变量,依然有效!

2. Clever方法实现

其实,对于重复点击这类问题,只需要一个状态标记就能够解决,但是我们的之前的方法只适用于单个** Button **按钮,对于多个按钮,如果我们这么去做,必然是大量的 Ctrl+C 和 Ctrl+V,想想都心累,更别说我还真的这么干过。

如果有一种一劳永逸的方法岂不是很好,对了,然后我们想到了封装,从** Button 组件内部去判断岂不是美妙,这样我们只需要替换xml中的 Button 就可以完美的解决大量的按钮点击事件。
既然,
Button **按钮的事件点击是通过

setOnClickListener(OnClickListener listener)

方法注册的,我们只需要在注册的时候,替换新的Listener,加上我们自定义事件判断就可以搞定。
比如:

public class OnNoRepeatButton extends Button
{
    public ButtonEx(final Context context)
    {
        super(context);
    }

    public ButtonEx(final Context context, final AttributeSet attrs)
    {
        super(context, attrs);
    }

    public ButtonEx(final Context context, final AttributeSet attrs, final int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public void setOnClickListener(final OnClickListener listener)
    {
        super.setOnClickListener(new OnNoRepeatClickListener(listener));
    }
}

我们的** OnNoRepeatClickListener **:

/**
 * 防止快速点击中多次触发事件的自定义OnClickListener
 */
public class OnNoRepeatClickListener implements OnClickListener
{
    private final OnClickListener mListener;

    private long lastClickTime = 0;

    public OnNoRepeatClickListener(final OnClickListener listener)
    {
        this.mListener = listener;
    }

    @Override
    public void onClick(final View v)
    {
        synchronized (this)
        {
            //判断当前点击时间与上一次点击时间的间隔
            if (System.currentTimeMillis() - this.lastClickTime > 1000)
            {
                if (this.mListener != null)
                    this.mListener.onClick(v);

                //处理完响应事件后记录时间确保下次响应
                this.lastClickTime = System.currentTimeMillis();
            }
        }
    }
}

Note: 代码中的** 1000 **单位是ms,具体的时间需要根据需求来定义。

3. Smart方法实现

Clever方法已经算是一个相对好的解决思路,但是如果我们的** Textview ,ImageView , View **等组件点击事件重复需要怎么解决呢?
也需要我们重写每一个的组件的

setOnClickListener(OnClickListener listener)

来实现。
那么,如果我们在重写了** Activity/Fragment **中重写

View.OnClickListener

方法,对点击事件时间进行判断,便可以减少对** View **组件的

setOnClickListener(OnClickListener listener)

方法的重写。

上代码:

interface IBaseView extends View.OnClickListener {

    /**
     * 初始化数据
     *
     * @param bundle 传递过来的bundle
     */
    void initData(final Bundle bundle);

    /**
     * 绑定布局
     *
     * @return 布局Id
     */
    int bindLayout();

    /**
     * 初始化view
     */
    void initView(final Bundle savedInstanceState, final View view);

    /**
     * 业务操作
     */
    void doBusiness();

    /**
     * 视图点击事件
     *
     * @param view 视图
     */
    void onWidgetClick(final View view);
}

BaseActivity.java

/**
 * 
 *     desc  : Activity基类
 * 
*/ public abstract class BaseActivity extends AppCompatActivity implements IBaseView { /** * 当前Activity渲染的视图View */ protected View contentView; /** * 上次点击时间 */ private long lastClick = 0; protected BaseActivity mActivity; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mActivity = this; Bundle bundle = getIntent().getExtras(); initData(bundle); setBaseView(bindLayout()); initView(savedInstanceState, contentView); doBusiness(); } protected void setBaseView(@LayoutRes int layoutId) { setContentView(contentView = LayoutInflater.from(this).inflate(layoutId, null)); } /** * 判断是否快速点击 * * @return {@code true}: 是
{@code false}: 否 */ private boolean isFastClick() { long now = System.currentTimeMillis(); if (now - lastClick >= 800) { lastClick = now; return false; } return true; } @Override public void onClick(final View view) { if (!isFastClick()) onWidgetClick(view); } }

总结


当然,Smart方法也不是最佳的解决方案,这样来做需要组件采用

setOnClickListener(this)

调用方式,让** Activity/Fragment **统一处理点击事件的响应,Clever和Smart的结合也是一个不错的选择。

Have fun , enjoy Coding...

你可能感兴趣的:(Android判断是否快速点击新思路)