Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OnTimeSet called also when dismissing TimePickerDialog

Today I was trying to use the TimePickerDialog but I noticed a couple of flaws.

  1. OnTimeSet is called also when the dialog is dismissed (by clicking outside, for example)
  2. OnTimeSet is called twice when the user taps the "Done" button

The API I'm using is 18.

Anyone else has experienced these problems? How did you solve them?

like image 819
Alessandro Roaro Avatar asked Oct 18 '13 15:10

Alessandro Roaro


5 Answers

You hould use already given method of View class:

new TimePickerDialog.OnTimeSetListener() {
    @Override
    public void onTimeSet(TimePicker view, int hour, int minute) {  
        if (view.isShown()) {
            // This method will return true only once...
        }
    }
};
like image 117
Ankur Chaudhary Avatar answered Sep 22 '22 15:09

Ankur Chaudhary


Faced the exact same issue today. Could not figure out why this was happening, but found a simple solution:

Method onTimeSet() is called once when dialog is dismissed and is called twice when Done button is clicked. Either way, there is one unwanted call to onTimeSet(). So I decided to always ignore the first call.

Here's the code:

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();
like image 37
Tony Avatar answered Sep 20 '22 15:09

Tony


To reiterate: This is a confirmed bug in Android for multiple Dialog types. Two workarounds have already been suggested, saving the state in a (instance) variable or asking the Dialog if it isShown(). But isShown() seems to be unreliable in Android 4.0.4 and saving the state gets messy if you want to re-show the dialog.
A better solution is to save the state inside the Dialog itself, because it is the same instance that calls the method:

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

It's clean and effective.

like image 23
leondepeon Avatar answered Sep 21 '22 15:09

leondepeon


Using count to avoid it. when TimePickDialog was selected more than twice, it should also work well.

            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);
like image 21
Moerdo Avatar answered Sep 20 '22 15:09

Moerdo


Thanks to Tony for posting a workaround. This works for most of the time but not always. We had released our app with this workaround (along with version checks); however this solution failed on Samsung Galaxy Note GT-8000 (Android 4.4.2). Default 4.4.2 devices have this bug and solution works however Samsung seems to have fixed this issue in 4.4.2 release so onTimeSet() is called only once that we ignore and second call never happened.

We are posting a solution that we applied today. Though I am not happy with the solution as it is another hack/workaround but it may help in scenarios where version check doesn't help and OEMs merge selective fixes.

Our earlier implementation was

                        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
                    }

Our New Implementation is

                        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
                    }

Hope it may help others.

like image 1
Gailu Avatar answered Sep 21 '22 15:09

Gailu