Android 4.1.2 dialogs are called twice

2020-08-10 07:15发布

问题:

I have this issue with my app when I call to show a dialog, it is being called twice somehow. This only happens with android 4.1 and above. Lower version works fine so I dont think it's any code issue.

Did you heard\encountered this issue before?

here the code:

Button edit = (Button) ad.findViewById(R.id.editBtn);
        edit.setTypeface(roboto);
        edit.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {

                setDate();
                ad.dismiss();
            }
        });

        ad.show();

        ad.setOnDismissListener(new OnDismissListener() {

            @Override
            public void onDismiss(DialogInterface dialog) {
                shiftsActivity.setPressed(true);

            }
        });
    }

    public void setDate() {
    // Initialize and open the set date dialog
    DatePickerDialog setDateDialog = new DatePickerDialog(Shifts.this,
            datePickerListener, dateAndTime.get(Calendar.YEAR),
            dateAndTime.get(Calendar.MONTH),
            dateAndTime.get(Calendar.DAY_OF_MONTH));

    setDateDialog.setTitle("Set Date");
    setDateDialog.show();

}

public void setStartTime() {

    TimePickerDialog setStartTimeDialog = new TimePickerDialog(Shifts.this,
            startTimePicker, dateAndTime.get(Calendar.HOUR),
            dateAndTime.get(Calendar.MINUTE), true);

    setStartTimeDialog.setTitle("Started At:");
    setStartTimeDialog.show();

}

public void setEndTime() {

    TimePickerDialog setEndTimeDialog = new TimePickerDialog(Shifts.this,
            setEndTime, dateAndTime.get(Calendar.HOUR),
            dateAndTime.get(Calendar.MINUTE), true);
    setEndTimeDialog.setTitle("Ended:");
    setEndTimeDialog.show();
}

TimePickerDialog.OnTimeSetListener startTimePicker = new TimePickerDialog.OnTimeSetListener() {

    @Override
    public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
        startIntHours = hourOfDay;
        startIntMinutes = minute;
        editStartTime = String.format("%02d", hourOfDay) + ":"
                + String.format("%02d", minute);
        setEndTime();

    }
};

TimePickerDialog.OnTimeSetListener setEndTime = new TimePickerDialog.OnTimeSetListener() {

    @Override
    public void onTimeSet(TimePicker view, int hourOfDay, int minute) {

        finishIntHours = hourOfDay;
        finsihIntMinutes = minute;

        if (finishIntHours < startIntHours) {
            finishIntHours = finishIntHours + Utility.HOURS_TIME_UNIT;
        }

        if (finsihIntMinutes < startIntMinutes) {
            finsihIntMinutes = finsihIntMinutes + Utility.MINUTES_TIME_UNIT;
        }

        totalHours = finishIntHours - startIntHours;
        totalMinutes = finsihIntMinutes - startIntMinutes;
        Log.i("TotalHours in time picker", "" + totalHours);
        Log.i("Totalminute in time picker", "" + totalMinutes);

        editEndTime = String.format("%02d", hourOfDay) + ":"
                + String.format("%02d", minute);

        replace(Shifts.view, Shifts.position);

    }
};

回答1:

According to your code, neither of those methods are ever called, because you never use the TimePickerDialogs.

That being said, there is a known issue related to the behavior of DatePickerDialog/TimePickerDialog that may be relevant: http://code.google.com/p/android/issues/detail?id=34833



回答2:

Here is a basic solution, for someone who needs a TimeChooserDialog, that does not call the listener twice, with basic options

public static AlertDialog getTimePickerDialog(Context context, final OnTimeSetListener listener, int hour, int minute, boolean is24HFormat) {
    AlertDialog.Builder builder = new AlertDialog.Builder(context);
    final TimePicker timePicker = new TimePicker(context);
    timePicker.setIs24HourView(is24HFormat);
    timePicker.setCurrentHour(hour);
    timePicker.setCurrentMinute(minute);
    builder.setView(timePicker);
    builder.setPositiveButton(android.R.string.ok, new OnClickListener() {
        @Override
        public void onClick(DialogInterface arg0, int arg1) {
            if(null != listener) {
                listener.onTimeSet(timePicker, timePicker.getCurrentHour(), timePicker.getCurrentMinute());
            }
        }
    });
    builder.setNegativeButton(android.R.string.cancel, null);
    return builder.create();
}


回答3:

If you look in the android source it appears that onTimeSet() gets called during onStop(). The dialog also calls onTimeSet() in it's onClick() method.

To get around this I had to override the dialogs dismiss and cancel functions to set a boolean which i checked if the onTimeSet was being called from the button click or dismiss/cancel



回答4:

The same issue is occurs with me for TimePicker. I solve that issue.

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

iShown() :

Returns the visibility of this view and all of its ancestors

Returns True if this view and all of its ancestors are VISIBLE



回答5:

I try it and it is work good with me if you still have the problem try to use The classic singleton

Something like this :) read more about it.

public void setStartTime() {

    TimePickerDialog setStartTimeDialog = NULL;
    if(setStartTimeDialog == null) {
       new TimePickerDialog(Shifts.this, startTimePicker, dateAndTime.get(Calendar.HOUR),dateAndTime.get(Calendar.MINUTE), true);

    setStartTimeDialog.setTitle("Started At:");
       }
    setStartTimeDialog.show();

}


回答6:

Don't use the built-in TimePickerDialog or DatePickerDialog. Instead create a custom dialog like what is shown here. It's simple and easy to use and just works!

        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        final TimePicker timePicker = new TimePicker(getActivity());
        builder.setTitle("Set Time");
        builder.setView(timePicker);
        builder.setNegativeButton("Cancel", new OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });
        builder.setPositiveButton("OK"), new OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                int minute = timePicker.getCurrentMinute();
                int hourOfDay = timePicker.getCurrentHour();
            }
        });
        builder.show();


回答7:

Rather than violate super.onClose() or making custom dialogs, I solve it with by wrapping real listener and extending TimePickerDialog that enabled and disables forwarding from wrapper to real listener. It's not a drop in replacement, but it's neat enough.

public class TimePickerDialogCustom extends TimePickerDialog
{
    protected TimePickerDialogOnTimeSetListenerWrapper listenerWrapper;

    public TimePickerDialogCustom(Context context,
            TimePickerDialogOnTimeSetListenerWrapper listener,
            int hourOfDay, int minute, boolean is24HourView)
    {
        super(context, listener, hourOfDay, minute, is24HourView);
        listenerWrapper = listener;
    }
    @Override
    protected void onStop()
    {
        if (listenerWrapper != null)
            listenerWrapper.enabled = false;
        super.onStop();
        if (listenerWrapper != null)
            listenerWrapper.enabled = true;
    }
    public static final class TimePickerDialogOnTimeSetListenerWrapper implements TimePickerDialog.OnTimeSetListener
    {
        private boolean enabled = true;
        private final TimePickerDialog.OnTimeSetListener delegate;

        public TimePickerDialogOnTimeSetListenerWrapper(TimePickerDialog.OnTimeSetListener delegate)
        {
            this.delegate = delegate;
        }
        @Override
        public void onTimeSet(TimePicker view, int hourOfDay, int minute)
        {
            if (enabled)
            {
                this.delegate.onTimeSet(view, hourOfDay, minute);
            }
        }
    }
}

Then to use it:

    TimePickerDialogCustom.TimePickerDialogOnTimeSetListenerWrapper listenerWrapper =
            new TimePickerDialogCustom.TimePickerDialogOnTimeSetListenerWrapper(realListener);
    // Create a new instance of DatePickerDialog and return it
    TimePickerDialogCustom dialog = new TimePickerDialogCustom(
            getActivity(),
            listenerWrapper,
            hourOfDay,
            minute,
            DateFormat.is24HourFormat(getActivity()));


回答8:

I faced this issue showing the timepicker twice. I have overriden the onStop() of TimePickerDialog and that solved the issue. Also you should not call super.onStop() in your overriden onStop().

@Override
public void onStop() {
    //super.onStop();
    Log.d(TAG, "onStop of starttime TimePickerDialog.");
}