【问题标题】:OnTimeSet called also when dismissing TimePickerDialog关闭 TimePickerDialog 时也会调用 OnTimeSet
【发布时间】:2013-10-27 11:51:12
【问题描述】:

今天我尝试使用TimePickerDialog,但我发现了一些缺陷。

  1. 关闭对话框时也会调用 OnTimeSet(例如,通过单击外部)
  2. OnTimeSet 在用户点击“完成”按钮时被调用两次

我使用的 API 是 18。

其他人遇到过这些问题吗?你是怎么解决的?

【问题讨论】:

    标签: android timepicker


    【解决方案1】:

    你应该使用已经给定的 View 类方法:

    new TimePickerDialog.OnTimeSetListener() {
        @Override
        public void onTimeSet(TimePicker view, int hour, int minute) {  
            if (view.isShown()) {
                // This method will return true only once...
            }
        }
    };
    

    【讨论】:

    • 谢谢,这是一个非常令人沮丧的问题!
    • 但是这个逻辑在三星 4.0.4 版本中不起作用。 view.isShown() 总是返回 false。
    • @ShankiBansal 是的,它不适用于 4.0.4 版本,因此您可以进行操作系统版本检查。如果版本低于果冻豆,则无需使用 view.isshown。如果您仍然遇到问题或找到其他方法,请告诉我。
    • 这肯定是公认的答案,这是一个非常令人沮丧的问题,我讨厌它,并且喜欢你的答案:)
    • 现在是 2017 年,但这个 bug 仍然没有被 google 解决。
    【解决方案2】:

    今天面临完全相同的问题。无法弄清楚为什么会发生这种情况,但找到了一个简单的解决方案:

    方法 onTimeSet() 在对话框关闭时调用一次,在单击完成按钮时调用两次。无论哪种方式,都会对 onTimeSet() 进行一次不必要的调用。所以我决定总是忽略第一个电话。

    代码如下:

    Calendar mcurrentTime = Calendar.getInstance();
    int hour = mcurrentTime.get(Calendar.HOUR_OF_DAY);
    int minute = mcurrentTime.get(Calendar.MINUTE);
    
    TimePickerDialog mTimePicker;
    mTimePicker = new TimePickerDialog(MainActivity.this, new TimePickerDialog.OnTimeSetListener() 
        {
            int callCount = 0;   //To track number of calls to onTimeSet()
    
            @Override
            public void onTimeSet(TimePicker timePicker, int selectedHour, int selectedMinute) 
            {
                 if(callCount == 1)    // On second call
                 {
                     timeString = selectedHour + ":" + selectedMinute + ":00";
                     Log.d("TEST", "Chosen time : "+ timeString);           
                 }
    
                 callCount++;    // Incrementing call count.
    
            }
        }, hour, minute, true);
    
        mTimePicker.setTitle("Pick Time");
        mTimePicker.show();
    

    【讨论】:

    • 我以同样的方式处理它(还有其他的吗?),但我讨厌这些 Android 错误。顺便说一句,callCount 为 1 时不应该将它重置为 0 吗?
    • callCount 不需要重置,因为每次打开日期选择器对话框时都会创建一个新的 mTimePicker 实例。
    • 被调用两次有点奇怪,但这是默认行为。这似乎是一个便宜的快速修复,肯定会使用它。
    • 在三星 4.0.4 版本中。 onTimeSet() 只会被调用一次。因此,您的逻辑将不再起作用。你应该在那里检查版本。
    【解决方案3】:

    重申:这是 Android 中针对多种 Dialog 类型的已确认错误。已经提出了两种解决方法,将状态保存在(实例)变量中或询问对话框是否为isShown()。但是isShown() 在 Android 4.0.4 中似乎不可靠,如果您想重新显示对话框,保存状态会变得很混乱。
    更好的解决方案是将状态保存在 Dialog 本身内部,因为它是调用该方法的同一个实例:

    public void onDateSet(DatePicker picker, int year, int monthOfYear, int dayOfMonth) {
        if (picker.getTag() == null) {
            picker.setTag("TAGGED");
            // Only gets called once per Dialog
        }
    }
    

    干净有效。

    【讨论】:

      【解决方案4】:

      使用计数来避免它。当 TimePickDialog 被选中两次以上时,它也应该可以正常工作。

                  TimePickerDialog tpd = new TimePickerDialog(this, new TimePickerDialog.OnTimeSetListener() {
                  int count = 0;
                  @Override
                  public void onTimeSet(TimePicker view, int setHour, int setMinute) {
                      if(count % 2 == 0) {
                         //set time here
                      }
                      count++;
      
                  } }, hour, minute, true);
      

      【讨论】:

      • 这个解决方案最好的一点是不需要检查版本。
      【解决方案5】:

      感谢 Tony 发布解决方法。这在大多数情况下都有效,但并非总是如此。我们已经使用此解决方法发布了我们的应用程序(以及版本检查);但是这个解决方案在三星 Galaxy Note GT-8000 (Android 4.4.2) 上失败了。默认的 4.4.2 设备有这个错误并且解决方案有效,但是三星似乎已经在 4.4.2 版本中修复了这个问题,所以 onTimeSet() 只被调用一次,我们忽略并且第二次调用从未发生过。

      我们发布了我们今天应用的解决方案。虽然我对该解决方案不满意,因为它是另一种黑客/解决方法,但在版本检查无济于事且 OEM 合并选择性修复的情况下,它可能会有所帮助。

      我们之前的实现是

                              if((android.os.Build.VERSION.SDK_INT >=
                                  Build.VERSION_CODES.ICE_CREAM_SANDWICH) &&
                                  (android.os.Build.VERSION.SDK_INT <
                                          Build.VERSION_CODES.LOLLIPOP)){
                              if(ccount == 1){
                                  // Do Your Processing
                                  count = 0;
                              }else{
                                  // Ignore event. Bug in Android API
                                  count++;
                              }
                          }else{
                              // Do Your Processing
                          }
      

      我们的新实现是

                              if((android.os.Build.VERSION.SDK_INT >=
                                  Build.VERSION_CODES.ICE_CREAM_SANDWICH) &&
                                  (android.os.Build.VERSION.SDK_INT <
                                          Build.VERSION_CODES.LOLLIPOP)){
                              StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
                              StackTraceElement e = stacktrace[4];
                              String methodName = e.getMethodName();
                              if(methodName.equals("onClick")){
                                  // Do Your Processing
                              }else{
                                  // Ignore event. Bug in Android API
                              }
                          }else{
                              // Do Your Processing
                          }
      

      希望它可以帮助其他人。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-12-03
        • 1970-01-01
        • 2012-12-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多