按钮点击多次触发

Button Click triggered multiple times

对我来说 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 回调完成后 - 甚至更晚。

另一个例子是

我真的不想每次出现这种情况都手动引入一个布尔标志。 我会想到像注释这样的东西,它允许我指定一个重置自动生成的布尔值的事件。请不要使用样板代码。

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

我以前遇到过这种情况。基本上,我最终实现了自己的 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);

}

并且在您的 class 中,您可以执行以下操作而不会危及您的实现(正常代码)

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
}

此致,

上面的解决方案很好。 但是当使用 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 快乐 ;)

我们在跨页面的 Android 应用程序中有看似类似的错误,点击按钮会调用某些服务端点。 一直在想为什么 Android 内置的点击绑定对于这样一个常见的用例会失败。在我们的案例中,事实证明这是完全不同的事情。是的,我们花了很多时间才最终找到真正的罪魁祸首。

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

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

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

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