OnTimeSet также вызывается при закрытии TimePickerDialog.

Сегодня я пытался использовать TimePickerDialog, но заметил пару недостатков.

  1. OnTimeSet вызывается также при закрытии диалогового окна (например, при щелчке снаружи)
  2. OnTimeSet вызывается дважды, когда пользователь нажимает кнопку «Готово».

Я использую API 18.

Кто-нибудь еще сталкивался с этими проблемами? Как вы их решили?


person Alessandro Roaro    schedule 18.10.2013    source источник


Ответы (5)


Сегодня столкнулся с точно такой же проблемой. Не мог понять, почему это происходит, но нашел простое решение:

Метод 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();
person Tony    schedule 12.12.2013
comment
Я справился с этим так же (есть ли другие?), но я ненавижу эти ошибки Android. Кстати, разве вы не должны сбросить callCount на 0, когда он равен 1? - person Alessandro Roaro; 12.12.2013
comment
callCount не нужно сбрасывать, так как новый экземпляр mTimePicker создается каждый раз, когда вы открываете диалоговое окно выбора даты. - person Tony; 13.12.2013
comment
Немного странно, что он вызывается дважды, но это поведение по умолчанию. Это кажется дешевым быстрым решением, которое определенно будет использоваться. - person kabuto178; 09.07.2014
comment
В версии самсунг 4.0.4. onTimeSet() будет вызываться только один раз. Так что ваша логика больше не работает. Вы должны поставить проверку версии там. - person Shanki Bansal; 29.01.2015

Вы должны использовать уже заданный метод класса View:

new TimePickerDialog.OnTimeSetListener() {
    @Override
    public void onTimeSet(TimePicker view, int hour, int minute) {  
        if (view.isShown()) {
            // This method will return true only once...
        }
    }
};
person Ankur Chaudhary    schedule 25.09.2014
comment
Спасибо, это была очень неприятная проблема! - person Jdruwe; 17.10.2014
comment
но эта логика не работает в версии Samsung 4.0.4. view.isShown() всегда возвращает false. - person Shanki Bansal; 27.01.2015
comment
@ShankiBansal да, он не работает в версии 4.0.4, поэтому для этого вы можете проверить версию ОС. если версия ниже, чем jelly bean, нет необходимости использовать view.issown. Если вы все еще сталкиваетесь с проблемой или нашли другой способ, дайте мне знать. - person Ankur Chaudhary; 28.01.2015
comment
Это наверняка должен быть принятый ответ. Это была действительно неприятная проблема, я ненавижу ее и люблю ваш ответ :) - person AbdelHady; 16.03.2015
comment
это 2017 год, но до сих пор эта ошибка не решена Google. - person KuLdip PaTel; 07.12.2017

Повторюсь: это подтвержденная ошибка в Android для нескольких типов диалогов. Уже были предложены два обходных пути: сохранение состояния в переменной (экземпляра) или запрос диалогового окна, если оно isShown(). Но isShown() кажется ненадежным в Android 4.0.4, и сохранение состояния становится беспорядочным, если вы хотите повторно отобразить диалоговое окно.
Лучшим решением является сохранение состояния внутри самого диалогового окна, потому что это тот же экземпляр, который вызывает метод:

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

Это чисто и эффективно.

person leondepeon    schedule 29.04.2015

Использование подсчета, чтобы избежать этого. когда 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);
person Moerdo    schedule 21.05.2014
comment
Лучшее в этом решении - нет необходимости проверять версию. - person Chintan Shah; 05.12.2016

Спасибо Тони за публикацию обходного пути. Это работает в большинстве случаев, но не всегда. Мы выпустили наше приложение с этим обходным решением (вместе с проверкой версии); однако это решение не помогло на Samsung Galaxy Note GT-8000 (Android 4.4.2). Устройства 4.4.2 по умолчанию имеют эту ошибку, и решение работает, однако Samsung, похоже, исправила эту проблему в выпуске 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
                    }

Надеюсь, это может помочь другим.

person Gailu    schedule 02.04.2016