Android上的快速点击事件处理

时间:2014-05-29 08:28:27

标签: android

如果你非常快速点击2个单独的按钮,甚至是同一个按钮,Android将处理两个点击事件。当它可以启动服务两次,或者显示对话两次,或者开始相互之间的活动等时,这就成了一个问题。

防止单个按钮双击的修复非常简单,答案就是StackOverflow。您只需检查是否已使用布尔标志单击该按钮,并停止处理任何进一步的单击事件。

我的问题是用户可能会快速按两个(或更多)不同的按钮(或列表项,或ActionBar项等)。处理“有按钮x被点击 - >更好地禁用按钮x,y,z”的每个组合将是非常乏味和容易出错。

有没有人有一个像样的解决方案?

2 个答案:

答案 0 :(得分:2)

我会投入我的.02,虽然这可能不适合作为一个体面的解决方案。它很简单,没有考虑到例如启用按钮,安排或任何其他复杂的操作。它可能会删除一些样板,例如禁用按钮,但需要付出丑陋try-finally语法的代价:

public final class EventLocker {

    private static Object lock;

    public static synchronized boolean lock(final Object object) {
        if (null == object) { throw new IllegalArgumentException("object must not be null"); }
        if (null == lock) {
            lock = object;
            return true;
        }
        return false;
    }

    public static synchronized boolean release(final Object object) {
        if (null != lock && lock.equals(object)) {
            lock = null;
            return true;
        }
        return false;
    }

}

然后,假设您希望在按钮上设置OnClickListener:

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        if (EventLocker.lock(view)) {
            try {
                doSomething();
            } finally {
                EventLocker.release(view);
            }
        }
    }
});

如果你一直使用锁定解锁习语,你可以保证例如按钮B释放锁定后,按钮B将不会执行任何操作。从好的方面来说,如果需要,可以很容易地添加自定义要求。


回答下面的第一条评论:

你是对的 - 在我的回答中没有特别提到这一点,我有点邋..

例如,每个onClick()事件都会发布到主线程队列中。有趣的是,它提出了一个我不可避免地要避免的话题​​;如果顺序处理按钮点击事件并且不离开主线程,则例如双击不是异常,而是在短时间内一个接一个地处理两个有效的动作。

确实没有任何问题 - 短暂的150毫秒可能没​​有意义,但10秒可能是一个完全可行的选择。在这些情况下,我认为最好确保onClick实现足够聪明,可以重用,重建或以任何其他方式处理手头的资源。

答案 1 :(得分:1)

  

如果你非常快速点击2个单独的按钮,甚至是同一个按钮,Android将处理两个点击事件。当它可以启动服务两次,或者显示对话两次,或者开始相互之间的活动等时,这就成了一个问题。

编写良好的用户界面是幂等的,通常是通过验证:

  • 如果您已经
  • ,请不要启动该服务
  • 如果对话框显示
  • ,则不显示对话框
  • 如果您已经做过并且尚未自行停止,请不要开始其他活动
  • 不要重新删除已删除的项目

在某些情况下,开发人员不担心完全幂等,因为框架会处理它(例如,给定一个编写良好的onStartCommand()方法,启动服务两次应该不是问题;你不能删除相同的_ID两次)。在某些情况下,开发人员不担心完全幂等,因为对用户的影响是非破坏性的(例如,开始两次活动)。在某些情况下,开发人员不担心这个问题,因为触发机制有效地阻止了重复的效果(例如,长按)。

在某些情况下,我们只是懒惰。 : - )

但验证应该是工作,而不是触发器。无论我们是否因按钮单击,操作项单击,列表行单击,设备震动,传入GCM消息等而启动服务,我们都需要确保以幂等方式处理工作。

  

我的问题是用户可能会快速按两个(或更多)不同的按钮(或列表项或ActionBar项等)。

这超越了幂等性。这也是不太可能的,因为用户只是不那么快地移动他们的手指 - 这是测试猴子将比普通人更多地遇到的事情。而且,AFAIK很少有开发人员担心的事情。

如果你真的想担心它,那么就拿出尽可能少的“担心”。例如,如果用户连续点击两个操作栏项,其中一个标记当前查看的详细信息作为收藏,另一个弹出对话框以允许用户将密码与当前查看的详细信息关联, 谁在乎?为什么这本质上无效?

但除此之外,是的,这将是乏味的。您需要跟踪所有可能的“不要快速连续执行此操作”并确定您是否在各种回调中遇到了“快速连续”案例(onClick()onListItemClick()onOptionsItemSelected())。许多代码可以被分解为某种EventMonitor,它可以了解您的业务规则,并可以报告您是否遇到了快速连续的情况。