【问题标题】:DatePicker.OnDateChangedListener called twiceDatePicker.OnDateChangedListener 调用了两次
【发布时间】:2012-09-08 07:13:00
【问题描述】:

我正在尝试创建一个应用程序,其中用户从 DatePicker 中选择一个日期,然后使用一些值更新一个列表。

我的 GUI 如下所示:

    <LinearLayout
    android:id="@+id/linearLayout1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center" >


    <DatePicker
        android:id="@+id/datePicker"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

<LinearLayout
    android:id="@+id/linearLayout2"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >



   <ListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1" >


    </ListView> 
</LinearLayout>

而我的 DatePicker 初始化和处理如下所示:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

    datePicker = (DatePicker) findViewById(R.id.datePicker);

    Calendar c = Calendar.getInstance();

    year = c.get(Calendar.YEAR);
    month = c.get(Calendar.MONTH);
    day = c.get(Calendar.DAY_OF_MONTH);

    datePicker.init(year, month, day, dateSetListener);
}

private DatePicker.OnDateChangedListener dateSetListener = new DatePicker.OnDateChangedListener() {

    public void onDateChanged(DatePicker view, int year, int monthOfYear,
            int dayOfMonth) {
         Calendar c = Calendar.getInstance();
         c.set(year, monthOfYear, dayOfMonth);
         System.out.println ("TEST");

    }
};

在 CatLog 中,我看到“TEST”字符串输出两次,每次我使用小部件上的 +/- 按钮时。可能是什么问题?

注意:我故意“禁用”了列表更新代码,以确保问题与 ListView 无关,如here

【问题讨论】:

标签: android events datepicker


【解决方案1】:

当我测试我的应用程序时,方法 onDateSet 在接受日期选择后调用了两次,在我取消时调用了一次。

我在 onDateSet 方法中添加了一个带有参数视图的验证,类似这样

@Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth){
    if (view.isShown()) {
        updateDate(year, monthOfYear, dayOfMonth);
    }
}

我希望你服务

【讨论】:

  • 你的答案是完美的......不需要创建额外的布尔变量来检查。
  • 这是一个黑客;拯救了我的一天;太棒了
  • 真正的问题是:到底为什么它会被调用两次?
  • 这是一个在Android 5.0中已经修复的bug,早期版本没有backport。所以使用这个解决方法。错误:code.google.com/p/android/issues/detail?id=34833
  • 如果我们使用上面的代码,android 5.0以上的设备有问题吗?
【解决方案2】:

我还没有设法找到一个巧妙的解决方法。我宁愿找到一种解决方法,因此该事件不会触发两次。解决方法如下:

int timesCalled = 1;

private DatePicker.OnDateChangedListener dateSetListener = new DatePicker.OnDateChangedListener() {

public void onDateChanged(DatePicker view, int year, int monthOfYear,
        int dayOfMonth) {
     Calendar c = Calendar.getInstance();
     c.set(year, monthOfYear, dayOfMonth);
     timesCalled += 1;

     if ((timesCalled % 2) == 0) {
        System.out.println ("TEST");
     }

}};

【讨论】:

  • 伙计,你必须接受@Cesardl 的回答并表现出一些体育精神,因为这个答案只是一种解决方法。
【解决方案3】:

我重写了 DatePickerDialog 对话框的 onClick 方法,而不是 onDateSet 回调,只处理 BUTTON_POSITIVE 点击。

public static class DatePickerFragment extends DialogFragment {
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        final Calendar c = Calendar.getInstance();
        int initialYear = c.get(Calendar.YEAR);
        int initialMonth = c.get(Calendar.MONTH);
        int initialDay = c.get(Calendar.DAY_OF_MONTH);
        return new DatePickerDialog(getActivity(), null, initialYear, initialMonth, initialDay) {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                if (which == BUTTON_POSITIVE) {
                    int year = getDatePicker().getYear();
                    int month = getDatePicker().getMonth();
                    int day = getDatePicker().getDayOfMonth();

                    //TODO: Do your logic here
                }
                super.onClick(dialog, which);
            }
        };
    }
}

代码保持清晰,但仍不清楚为什么 onDateSet 被调用两次。

【讨论】:

    【解决方案4】:
    private DatePicker.OnDateChangedListener dateSetListener = new DatePicker.OnDateChangedListener() { 
    
        public void onDateChanged(DatePicker view, int year, int monthOfYear, 
                int dayOfMonth) { 
             Calendar c = Calendar.getInstance(); 
             c.set(year, monthOfYear, dayOfMonth); 
             updateDisplay();
    
        } 
    }; 
    
    
    TextView datetext;
    datetext = (TextView) findViewById(R.id.selected_date);
    
    
    private void updateDisplay() {
            this.datetext.setText(new StringBuilder()
                    // Month is 0 based so add 1
                    .append(mMonth + 1).append("-").append(mDay).append("-")
                    .append(mYear).append(" "));
        }
    

    【讨论】:

    • 感谢您的回答,但这似乎并不能解决我的问题。我没有更新显示的问题。相反,我将显示更新两次,而不是一次。
    • 试试这个... DatePickerDialog.OnDateSetListener mDateSetListener = new DatePickerDialog.OnDateSetListener() { public void onDateSet(
    • 问题是 datePicker.init 接受 DatePicker.OnDateChangedListener 作为最后一个参数,而不是 DatePickerDialog.OnDateSetListener,因此它不起作用:S
    • 我发现问题与更新视图无关,而是与创建对话框时有关,所以如果要控制效果,那么解决方案在于控制对话框的创建和可见性取决于您使用哪种方法填充对话框
    【解决方案5】:

    也许可以通过添加实例变量来修改监听器,这样你就可以检查它们是否与上次调用该方法时不同:

    final DatePickerDialog datePickerDialog = new DatePickerDialog (this, new DatePickerDialog.OnDateSetListener()
        {   
            private int year;
            private int month;
            private int day;
    
            @Override
            public void onDateSet (DatePicker view, int year, int monthOfYear, int dayOfMonth)
            {
                if (this.year == year && this.month == monthOfYear && this.day == dayOfMonth)
                    return;
    
                this.year = year;
                this.month = monthOfYear;
                this.day = dayOfMonth;
    
                calendar.set (year, month, day);
                int index = officeCalendar.indexOfKey (calendar.getTimeInMillis ());
    
                if (index > -1)
                    viewPager.setCurrentItem (index);
            }
        }, calendar.get (Calendar.YEAR), calendar.get (Calendar.MONTH), calendar.get (Calendar.DATE));
    

    【讨论】:

      【解决方案6】:
      private DatePicker.OnDateChangedListener dateSetListener = new DatePicker.OnDateChangedListener() {
          boolean fired = false;
          public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
               if (fired == true){
      //Twince
               }
               else{
                   Calendar c = Calendar.getInstance();
                   c.set(year, monthOfYear, dayOfMonth);
                   System.out.println ("TEST");
               }
      
          }
      };
      

      【讨论】:

        【解决方案7】:

        请在此处查看我的答案。它适用于 TimePickerDialog,但也适用于 DatePickerDialog。您可以创建一个自定义对话框,它几乎同样快速、简单且有效。

        https://stackoverflow.com/a/25672760/940450

        【讨论】:

          【解决方案8】:

          无需在果冻豆下添加此代码

          @Override
          public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth){
              if (view.isShown()) {
                  updateDate(year, monthOfYear, dayOfMonth);
              }
          }
          

          【讨论】:

            【解决方案9】:

            我创建了一个 SupportDatePickerDialog.kt 类

                import android.app.DatePickerDialog
                import android.content.Context
                import android.os.Build
                import android.widget.DatePicker
                import androidx.appcompat.view.ContextThemeWrapper
                
                /**
                 * Support [DatePickerDialog]
                 * for working around Samsung 5 [java.util.IllegalFormatConversionException] bug.
                 * > Fatal Exception: java.util.IllegalFormatConversionException: %d can't format java.lang.String arguments
                 * http://stackoverflow.com/a/31855744/570168
                 * for OnDateSetListener called twice bug
                 * https://stackoverflow.com/questions/12436073/datepicker-ondatechangedlistener-called-twice
                 *
                 */
                
                
                
                class SupportDateSetListener(private val function: (DatePicker, Int, Int, Int) -> Unit) : DatePickerDialog.OnDateSetListener {
                    override fun onDateSet(view: DatePicker, year: Int, month: Int, dayOfMonth: Int) {
                        if (view.isShown) {
                            function.invoke(view, year, month, dayOfMonth)
                        }
                    }
                }
                
                class SupportDatePickerDialog(context: Context, listener: SupportDateSetListener, year: Int, month: Int, dayOfMonth: Int) : DatePickerDialog(fixContext(context), listener, year, month, dayOfMonth) {
                    companion object {
                        /**
                         * Wraps the [Context] to use the holo theme to avoid stupid bug on Samsung devices.
                         */
                        @Suppress("DEPRECATION")
                        private fun fixContext(context: Context): Context {
                            return if (isBrokenSamsungDevice) {
                                ContextThemeWrapper(context, android.R.style.Theme_Holo_Light_Dialog)
                            } else {
                                context
                            }
                        }
                
                        /**
                         * Affected devices:
                         * - Samsung 5.0
                         * - Samsung 5.1
                         *
                         * @return true if device is affected by this bug.
                         */
                        @Suppress("SpellCheckingInspection")
                        private val isBrokenSamsungDevice: Boolean
                            get() = (Build.MANUFACTURER.equals("samsung", ignoreCase = true)
                                    && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1)
                    }
                }
            

            用法:

            val calendar = Calendar.getInstance()
            val supportDatePickerDialog = SupportDatePickerDialog(this, SupportDateSetListener { datePicker: DatePicker, year: Int, month: Int, dayOfMonth: Int ->
                //TODO
            }, calendar[Calendar.YEAR], calendar[Calendar.MONTH], calendar[Calendar.DAY_OF_MONTH])
            
            supportDatePickerDialog.show()
            

            【讨论】:

              猜你喜欢
              • 2017-06-25
              • 2013-01-21
              • 2016-04-27
              • 2019-02-27
              • 1970-01-01
              • 2019-12-04
              • 2018-09-15
              • 2012-10-10
              • 1970-01-01
              相关资源
              最近更新 更多