質問

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?

役に立ちましたか?

解決 2

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();

他のヒント

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...
        }
    }
};

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.

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);

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.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top