时间选择器中onDateSet/onTimeSet执行两次

来源:互联网 发布:js是什么文件 编辑:程序博客网 时间:2024/06/11 13:26

一 编写目的

           虽然目前有很多的时间选择控件可以给开发者使用,但有的时候由于使用行业,手机页面布局,手机屏幕等因素,我们还是需要使用android自带的时间选择控件。我最近使用系统时间选择控件的时候,发现了一个问题,就是高版本的系统中onDateSet方法会调用两次,这就意味着低版本中在onDateSet中实现的逻辑在高版本中会执行两次,这样就会给我们软件的兼容问题带来一些麻烦,因此这个地方把解决方法记录下,方便大家学习。

二 问题原因

          我手中有几台不同系统版本的手机,发现在4.3系统后的(下面就是4.1版本,4.2没测试过)版本中运行测试代码的时候,onDateSet中打印日志执行两次,而低版本的只执行了一次,这就说明很有可能是高版本系统在这个地方做了修改,因此我去查阅了下系统源码,对比一下,发现了其中问题。
低版本的源码:

    public void onClick(DialogInterface dialog, int which) {        if (mCallBack != null) {            mDatePicker.clearFocus();            mCallBack.onDateSet(mDatePicker, mDatePicker.getYear(),                     mDatePicker.getMonth(), mDatePicker.getDayOfMonth());        } }

就是说点击确定或取消按钮的时候会执行onDateSet方法。
高版本的源码:

    public void onClick(DialogInterface dialog, int which) {        tryNotifyDateSet();    }    private void tryNotifyDateSet() {        if (mCallBack != null) {            mDatePicker.clearFocus();            mCallBack.onDateSet(mDatePicker, mDatePicker.getYear(),                    mDatePicker.getMonth(), mDatePicker.getDayOfMonth());        }    }    @Override    protected void onStop() {        tryNotifyDateSet();        super.onStop();    }

从此源码中可以看出,相较于低版本的源码,高版本的源码中对应对话框的停止(onStop)也做了调用onDateSet方法,从而使点击确定或取消按钮时,该方法被执行了两次。

三 解决

          比较两份源码,我们很容易得出一个解决方法,就是把高版本的onStop干掉。对头,我就是这么处理的,重载onStop方法,将里面的super.onStop()去掉。对于无其他特殊要求的情况下,这种貌似是没有副作用的,而且,我这样用后到目前为止也没有副作用体现出来。以下是重载方法:

  public static class MyDatePickDialog extends DatePickerDialog {public MyDatePickDialog(Context context, OnDateSetListener callBack,int year, int monthOfYear, int dayOfMonth) {super(context, callBack, year, monthOfYear, dayOfMonth);// TODO Auto-generated constructor stub}public MyDatePickDialog(Context context, int theme,OnDateSetListener callBack, int year, int monthOfYear,int dayOfMonth) {super(context, theme, callBack, year, monthOfYear, dayOfMonth);// TODO Auto-generated constructor stub}@Overrideprotected void onStop() {// TODO Auto-generated method stub}}

同理,TimePickerDialog的解决方式和这个一样,就不累述了。

四 一个自定义的时间选择示例

            功能:通过继承EditText,达到点击输入框(或者调用里面的触发时间),然后弹出日期供选择,选完日期后,接着弹出时间来供选择,最后将选择的时间日期填写到输入框中。以下是代码:

package com.urovo.stocity.view.custom;import java.util.Calendar;import java.util.Date;import utils.DateUtil;import android.app.DatePickerDialog;import android.app.DatePickerDialog.OnDateSetListener;import android.app.Dialog;import android.app.TimePickerDialog;import android.app.TimePickerDialog.OnTimeSetListener;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.View;import android.widget.DatePicker;import android.widget.EditText;import android.widget.TimePicker;/** * input method will need to run in a limited "generate key events" mode. *  *  * @author admin *  */public class DateTimeEditText extends EditText implements OnDateSetListener,OnTimeSetListener {public MyDatePickDialog Dlg;public Dialog timeDialog;private Context context;private String timeStr;public DateTimeEditText(Context context) {super(context);this.context = context;setListener();}public DateTimeEditText(Context context, AttributeSet attrs) {super(context, attrs);this.context = context;setListener();}private void setListener() {this.setFocusable(false);this.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubinitCalendar();Dlg.show();}});}public void dateSelect() {// 此方法为弹出时间选择对话框,可在外部调用initCalendar();Dlg.show();}private void initCalendar() {String dateStr = this.getText().toString().trim();Date date = DateUtil.parseCompleteDate(dateStr);if (date == null) {// 如果输入框内初始为空,则将当前时间初始为日期时间date = new Date();}Calendar d = Calendar.getInstance();d.setTimeInMillis(date.getTime());// 初始化时间选择器int year = d.get(Calendar.YEAR);int month = d.get(Calendar.MONTH);int day = d.get(Calendar.DAY_OF_MONTH);Dlg = new MyDatePickDialog(context, this, year, month, day);Dlg.setCanceledOnTouchOutside(false);timeDialog = new MyTimePickerDialog(context, this,d.get(Calendar.HOUR_OF_DAY), d.get(Calendar.MINUTE), true);timeDialog.setTitle("请选择时间");}@Overridepublic void onDateSet(DatePicker view, int year, int monthOfYear,int dayOfMonth) {// TODO Auto-generated method stubtimeStr = year + "-"+ (monthOfYear < 9 ? "0" + (monthOfYear + 1) : monthOfYear + 1)+ "-" + (dayOfMonth < 10 ? "0" + dayOfMonth : dayOfMonth) + " ";timeDialog.show();Log.e("aa", "onDateSet");}@Overridepublic void onTimeSet(TimePicker view, int hourOfDay, int minute) {// TODO Auto-generated method stubtimeStr += (hourOfDay < 10 ? "0" + hourOfDay : hourOfDay) + ":"+ (minute < 10 ? "0" + minute : minute) + ":00";DateTimeEditText.this.setText(timeStr);Log.e("aa", "onTimeSet");}// 重写DatePickerDialog以避免两次执行onDateSet方法public static class MyDatePickDialog extends DatePickerDialog {public MyDatePickDialog(Context context, OnDateSetListener callBack,int year, int monthOfYear, int dayOfMonth) {super(context, callBack, year, monthOfYear, dayOfMonth);// TODO Auto-generated constructor stub}public MyDatePickDialog(Context context, int theme,OnDateSetListener callBack, int year, int monthOfYear,int dayOfMonth) {super(context, theme, callBack, year, monthOfYear, dayOfMonth);// TODO Auto-generated constructor stub}@Overrideprotected void onStop() {// TODO Auto-generated method stub}}public static class MyTimePickerDialog extends TimePickerDialog {public MyTimePickerDialog(Context context, OnTimeSetListener callBack,int hourOfDay, int minute, boolean is24HourView) {super(context, callBack, hourOfDay, minute, is24HourView);// TODO Auto-generated constructor stub}public MyTimePickerDialog(Context context, int theme,OnTimeSetListener callBack, int hourOfDay, int minute,boolean is24HourView) {super(context, theme, callBack, hourOfDay, minute, is24HourView);// TODO Auto-generated constructor stub}@Overrideprotected void onStop() {// TODO Auto-generated method stub}}}

五 结束

           一个小小的总结,希望能帮到大家。

0 0
原创粉丝点击