【问题标题】:Button Click triggered multiple times多次触发按钮点击
【发布时间】:2016-07-21 11:34:42
【问题描述】:

对我来说,Android 应用程序中的一个常见问题似乎是,点击事件可能会被触发多次,而实际上它们不应该触发。

我正在使用 Butterknife - 考虑以下示例

@OnClick(R.id.button_foto_aufnehmen)
protected void takePicture() {
  m_camera.takePicture();
}

带有一些布局的相机应用程序包含

    <SurfaceView
        android:id="@+id/surface_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    ...

    <ImageButton
        android:id="@+id/button_foto_aufnehmen"
        .../>

现在应该不可能再次单击该按钮,至少在 onPictureTaken 回调完成之后 - 甚至更晚。

另一个例子是

我真的不想每次出现这种情况时都手动引入布尔标志。 我会想到类似注释的东西,它允许我指定一个重置自动生成的布尔值的事件。请提供除样板代码以外的任何内容。

那么这里的最佳做法是什么(特别要记住黄油刀的用法)?

【问题讨论】:

  • 我认为唯一也是最好的解决方案是使用布尔标志。
  • 请发布您的 XML。
  • 我相信每次手动出现时使用布尔标志是一个可怕的想法。我希望有一个自动执行 boolena 标志的注释。你的意思是XML布局?那相当大 - 我将不得不举一个小例子 - 有没有办法通过 XML 解决它?

标签: android butterknife


【解决方案1】:

上面的解决方案非常好。 但是使用 Kotlin 的力量会变得更好

1) 创建 SafeClikc 监听器

class SafeClickListener(
        private var defaultInterval: Int = 1000,
        private val onSafeCLick: (View) -> Unit
) : View.OnClickListener {

    private var lastTimeClicked: Long = 0

    override fun onClick(v: View) {
        if (SystemClock.elapsedRealtime() - lastTimeClicked < defaultInterval) {
            return
        }
        lastTimeClicked = SystemClock.elapsedRealtime()
        onSafeCLick(v)
    }
}

2) 添加扩展功能使其适用于任何视图,这将创建一个新的 SafeClickListener 并将工作委托给它

fun View.setSafeOnClickListener(onSafeClick: (View) -> Unit) {

    val safeClickListener = SafeClickListener {
        onSafeClick(it)
    }
    setOnClickListener(safeClickListener)
}

3) 现在使用起来非常方便

settingsButton.setSafeOnClickListener {
    showSettingsScreen()
}

快乐的 Kotlin ;)

【讨论】:

    【解决方案2】:

    我以前也遇到过这种情况。基本上,我最终实现了自己的 CustomClickListener 并在允许触发触发器之前设置了特定时间间隔(例如 1000 毫秒)的阈值。 基本上,当您单击按钮并触发侦听器时,它会检查触发器是否在您定义的过去时间量内执行,如果没有,它将触发它。

    public class CustomClickListener implements View.OnClickListener {
    
        protected int defaultInterval;
        private long lastTimeClicked = 0;
    
        public CustomClickListener() {
            this(1000);
        }
    
        public CustomClickListener(int minInterval) {
            this.defaultInterval = minInterval;
        }
    
        @Override
        public void onClick(View v) {
            if (SystemClock.elapsedRealtime() - lastTimeClicked < defaultInterval) {
                return;
            }
            lastTimeClicked = SystemClock.elapsedRealtime();
            performClick(v);
        }
    
         public abstract void performClick(View v);
    
    }
    

    在您的课堂上,您可以执行以下操作而不会危及您的实现(普通代码)

    myButton = (Button) findViewById(R.id.my_button);
    myButton.setOnClickListener(new CustomClickListener() {
        @Override
        public void performClick(View view) {
            // do stuff
        }
    });
    

    或者通过使用 ButterKnife 实现(我还没有测试过,因为我目前没有可用的 Android Studio,所以如果它有效,请告诉我):

    @Bind(R.id.my_button)
    Button myButton;
    
    @OnClick(R.id.button)
    @Override
    public void performClick(View view) {
         // do stuff
    }
    

    问候,

    【讨论】:

    • 你能把它和黄油刀一起用吗? :)
    • 谢谢 - 我还没有机会尝试,但我仍然喜欢这个想法。据我所知,@Onclick 装饰器适用于具有适当签名的任何方法 - 我不确定自定义侦听器中的覆盖方法将如何表现 - 我想 butterknive 会动态创建自己的 ClickListener,这可能会危及它。 - 周一看看能不能试试。
    • 使用我们自己的监听器/构造器始终是保证一定程度控制的好方法。从最近的 ButterKnife 中,我注意到在接下来的几个月里,关于听众和事件的一些变化和改进即将到来。我自己喜欢将 ButterKnife 混合用于简单和基本的东西,以及自定义构造和实现。无论哪种方式,我真的对这个案例特别好奇,因为我自己有一些使用叠加层运行的活动(比如我的自定义相机)。如果您对此事得出任何优雅的结论,请告诉我。
    【解决方案3】:

    我们在一个 Android 应用程序的页面中似乎存在类似的错误,其中按钮单击会调用某个服务端端点。 一直在想,为什么 Android 内置的点击绑定会因为如此常见的用例而失败。结果在我们的案例中实际上是一个非常不同的事情。是的,我们花了很多时间才最终抓住真正的罪魁祸首。

    这是 Volley 库的超时值,即默认 2.5 秒,而我们的慢速服务器端端点需要超过 10 秒。 单击时我们的按钮正在调用一些服务器端点。比如说,点击一个按钮就可以预约。我们也看到重复的约会被预订了,即使是一次点击也是如此。超时将根据默认重试计数重试。默认情况下,重试计数为 1,因此每当我们的端点花费超过 2.5 秒时,Volley 将通过重新发布相同的请求并因此重复我们的操作来重试。 因此,这是按钮单击 + Volley 的问题,默认超时 + 端点花费的时间超过超时秒数。 解决办法是

    1. 在我们将请求添加到队列之前,通过设置重试策略来调整 Volley 的超时。 stringRequest.setRetryPolicy(新 DefaultRetryPolicy( 10000,//非默认超时,以毫秒为单位 DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT)); requestQueue.add(stringRequest);

    2. 提高我们服务器端端点的性能以快速响应客户端。

    希望这可以帮助那些在同一条船上航行或正在航行但像我们一样无能为力的人:)

    【讨论】:

      猜你喜欢
      • 2017-03-08
      • 2018-11-08
      • 2012-08-06
      • 1970-01-01
      • 1970-01-01
      • 2014-09-19
      • 1970-01-01
      • 1970-01-01
      • 2012-04-05
      相关资源
      最近更新 更多