【问题标题】:Android: Prevent multiple onClick events on a button (that has been disabled)Android:防止按钮上的多个 onClick 事件(已禁用)
【发布时间】:2012-06-01 09:57:27
【问题描述】:

一个按钮触发一个只能被调用一次的动作。在执行操作之前,该按钮被禁用并隐藏在 onClick 处理程序中:

someButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        someButton.setEnabled(false);
        someButton.setClickable(false);
        someButton.setVisibility(View.GONE);
        performTaskOnce();
        }
    });

private void performTaskOnce() {
    Log.i("myapp", "Performing task");
    //Do something nontrivial that takes a few ms (like changing the view hierarchy)
}

即使按钮立即被禁用,仍然可以通过快速点击多次来触发多个“onClick”事件。 (即performTaskOnce 被多次调用)。似乎在按钮实际禁用之前 onClick 事件已排队。

我可以通过检查每个单独的 onClick 句柄是否已禁用相应的按钮来解决此问题,但这似乎是一个 hack。有没有更好的方法来避免这个问题?

该问题出现在 Android 2.3.6 上,我无法在 Android 4.0.3 上重现它。但鉴于 4.x 设备的稀有性,因此不能排除旧设备。

【问题讨论】:

  • 这个问题困扰了我好几天..

标签: java android user-interface


【解决方案1】:

您可以在单击按钮时将布尔变量设置为 true,并在完成处理单击时将其设置为 false。

这样您可以忽略多次点击,而不必禁用按钮,可能避免烦人的按钮闪烁。

boolean processClick=true;
someButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        if(processClick)
         {
        someButton.setEnabled(false);
        someButton.setClickable(false);
        someButton.setVisibility(View.GONE);
        performTaskOnce();
         }
        processClick=false; 
        }
    });

private void performTaskOnce() {
    Log.i("myapp", "Performing task");
    //Do something nontrivial that takes a few ms (like changing the view hierarchy)
}

【讨论】:

  • 这似乎最简单。在 iOS 中,UIApplication 类有一个可以全局执行此操作的“beginIgnoringInteractionEvents”消息。这有时会很好。但是,我找不到适用于 Android 的等价物。您还可以使用简单的守卫“if (!processClick) return;”。这样可以减少嵌套。
  • @DaveCameron +1 完全同意你的看法
【解决方案2】:

为了保留DRY:

// Implementation
public abstract class OneShotClickListener implements View.OnClickListener {
    private boolean hasClicked;

    @Override public final void onClick(View v) {
        if (!hasClicked) {
            onClicked(v);
            hasClicked = true;
        }
    }

    public abstract void onClicked(View v);
}

// Usage example
public class MyActivity extends Activity {
    private View myView;

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        myView.setOnClickListener(new OneShotClickListener() {
            @Override public void onClicked(View v) {
                // do clicky stuff
            }
        });
    }
}

【讨论】:

    【解决方案3】:

    有点晚了,但这可能对某人有用。就我而言,我这样称呼另一项活动;

    声明一个布尔值;

    boolean clickable;
    

    在点击监听器中;

    if(clickable){
       // Launch other activity
       clickable = false;
    }
    

    在调用 onResume 时启用;

    @Override
    public void onResume() {
        Log.e(TAG, "onResume");
        super.onResume();
        clickable = true;
    }
    

    【讨论】:

      【解决方案4】:

      您可以使用RxView(com.jakewharton.rxbinding2.view.RxView) 是由 Jake Wharton 创建的围绕 RxJava 的扩展。

      要将其集成到项目中,您应该使用implementation 'com.jakewharton.rxbinding3:rxbinding:3.1.0'

      简单的Java用法:

      RxView.clicks(yourButton)
          .sample(500, TimeUnit.MILLISECONDS)
          .subscribe { action() }
      

      Kotlin 你可以创建扩展函数来处理你的点击:

      View.singleClick(action: () -> Any) {
          RxView.clicks(this)
              .sample(500, TimeUnit.MILLISECONDS)
              .subscribe { action() }
      }
      

      示例:

      科特林

      yourButton.singleClick({
          //do some stuff here
      })
      

      Java

      SingleClickListenerKt.singleClick(yourButton, () -> {
          doSomeStuff();
          return null;
          });
      

      注意:如果你愿意,你可以使用任何 RxJava 操作符,比如debounce, map, first,等等。

      【讨论】:

        【解决方案5】:

        声明一个变量 并将其用作

         boolean boo = false;
         someButton.setOnClickListener(new OnClickListener() {
         @Override
         public void onClick(View v) {
         if(boo==false){
            someButton.setEnabled(false);
            someButton.setClickable(false);
            someButton.setVisibility(View.GONE);
            boo = true;
         }
        
        
            }
        });
        

        这样可以防止您的按钮被多次点击

        希望对你有帮助

        【讨论】:

        • 为此使用 int 并递增它,不如标志清晰。您还没有展示如何/何时将其设置回零。另外,为什么是类变量而不是实例变量?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-05-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-19
        • 2018-11-19
        相关资源
        最近更新 更多