2013-04-10 64 views
1

我正在使用时间选择器让用户输入所需的时间来执行特定任务,我正在使用支持库中提供的DialogFragment类来向后兼容较旧的Android版本。TimePicker onTimeSet未被调用

这里是我的代码来创建TimePickerFragment类,在一个单独的文件中创建,摘自:http://developer.android.com/guide/topics/ui/controls/pickers.html

package com.calls.only; 
import java.util.Calendar; 
import android.app.Dialog; 
import android.app.TimePickerDialog; 
import android.os.Bundle; 
import android.support.v4.app.DialogFragment; 
import android.widget.TimePicker; 


public class TimePickerFragment extends DialogFragment 
          implements TimePickerDialog.OnTimeSetListener { 

    @Override 
    public Dialog onCreateDialog(Bundle savedInstanceState) { 
     // Use the current time as the default values for the picker 
     final Calendar c = Calendar.getInstance(); 
     int hour = c.get(Calendar.HOUR_OF_DAY); 
     int minute = c.get(Calendar.MINUTE); 

     // Create a new instance of TimePickerDialog and return it 
     return new TimePickerDialog(getActivity(), this, hour, minute, false); 
    } 

    public void onTimeSet(TimePicker view, int hourOfDay, int minute) { 
     // Do something with the time chosen by the user 
    } 
} 

主要活动:

package com.calls.only; 


import java.util.Calendar; 
import java.util.TimeZone; 
import android.os.Bundle; 
import android.app.AlarmManager; 
import android.app.PendingIntent; 
import android.content.Context; 
import android.content.Intent; 
import android.support.v4.app.FragmentActivity; 
import android.support.v4.app.DialogFragment; 
import android.view.Menu; 
import android.view.View; 
import android.widget.RadioButton; 
import android.widget.TextView; 

public class MainActivity extends FragmentActivity { 

public void InputStartTime(View v) { 
    DialogFragment newFragment = new TimePickerFragment(); 
    newFragment.show(getSupportFragmentManager(), "timePicker"); 

} 

private TimePickerDialog.OnTimeSetListener mTimeSetListener = 
     new TimePickerDialog.OnTimeSetListener() { 
        //Overriding onTimeSet causes an error, see below 
      public void onTimeSet(TimePicker view, int hourOfDay, int minute) { 
       Log.i("TimePicker", "Time picker set!"); 
      } 
     }; 

public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

} 

@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    getMenuInflater().inflate(R.menu.activity_main, menu); 
    return true; 
} 
} 

的onTimeset方法不被称为我可以从日志中看到,如果我尝试重写此方法,则会收到以下错误: “NewProderDialog.OnTimeSetListener(){}类型的onTimeSet(TimePicker,int,int)方法必须覆盖超类方法”

谁能告诉我问题是什么? 我一直在努力弄明白,它让我感到很沮丧!

+0

我测试了代码,并且它在'TimePickerFragment'类中的'onTimeSet'上面加上了'@ override',可以正常工作。 MainActivity中的监听器永远不会被调用,因为您没有在任何地方使用它。你总是可以在'TimePickerFragment'类中创建自己的接口,将时间发送到'MainActivity'。 – Naveen 2013-04-10 04:17:19

回答

4

the onTimeset method is not being called as I can see from the log

嗯,这是因为当你创建TimePickerDialog,您提供的片段OnTimeSetListener

return new TimePickerDialog(getActivity(), this, hour, minute, false); 
              ^

换句话说:你没有看到日志语句,因为在你的活动mTimeSetListener变量永远不会被设置为您在片段中创建的对话框的侦听器。

您可以通过将片段附加到您的MainActivity的活动,或者如果您更喜欢更可重用的东西,通过接口进行回调来轻松解决此问题。在这种情况下,您可以重新使用OnTimeSetListener接口,但也可以设置自己的接口,例如将Calendar对象传递回活动,而不是原始小时/分钟值。

在它的最基本的形式,它看起来有点像这样:

public class TimePickerFragment extends DialogFragment { 

    @Override public Dialog onCreateDialog(Bundle savedInstanceState) { 
     // ... omitted 

     if (!(getActivity() instanceof OnTimeSetListener)) throw new IllegalStateException("Activity should implement OnTimeSetListener!"); 
     OnTimeSetListener timeSetListener = (OnTimeSetListener) getActivity(); 

     // Create a new instance of TimePickerDialog and return it 
     return new TimePickerDialog(getActivity(), timeSetListener, hour, minute, false); 
    } 
} 

,然后让MainActivity实现同样的接口,在使用匿名内部类的代替:

public class MainActivity extends FragmentActivity implements TimePickerDialog.OnTimeSetListener { 

    @Override public void onTimeSet(TimePicker view, int hourOfDay, int minute) { 
     Log.i("TimePicker", "Time picker set!"); 
    } 
} 

更新:正如评论中所述,要启用对多个选择器的支持,您有几个选项。一个是跟踪托管活动中显示的对话框;如果只需要区分两个选择器,布尔值将会很好,否则枚举将是实现两个以上状态的适当方式。您需要确保在配置更改期间保留这条信息,尽管...

但是,我更喜欢做的是,能够确定在onTimeSet(...)中返回的结果的来源通过给每个选择器提供一个id。然后将该id包含在结果中,以便我们可以确定它来自哪里。我将概述以下总体思路:

public class TimePickerFragment extends DialogFragment implements OnTimeSetListener { 

    private int mId; 
    private TimePickerDialogListener mListener; 

    private static TimePickerFragment newInstance(int id) { 
     Bundle args = new Bundle(); 
     args.putInt("picker_id", id); 
     TimePickerFragment fragment = new TimePickerFragment(); 
     fragment.setArguments(args); 
     return fragment; 
    } 

    @Override public Dialog onCreateDialog(Bundle savedInstanceState) { 
     // ... omitted 

     mId = getArguments().getInt("picker_id"); 
     mListener = getActivity() instanceof TimePickerDialogListener ? (TimePickerDialogListener) getActivity() : null; 

     // Create a new instance of TimePickerDialog and return it 
     return new TimePickerDialog(getActivity(), this, hour, minute, false); 
    } 

    @Override public void onTimeSet(TimePicker view, int hourOfDay, int minute) { 
     if (mListener != null) mListener.onTimeSet(mId, view, hourOfDay, minute); 
    } 

    public static interface TimePickerDialogListener { 
     public void onTimeSet(int id, TimePicker view, int hourOfDay, int minute); 
    } 

} 

我们在前面已经改变的是有自身注册为OnTimeSetListener的对话框中,它会在数据通过TimePickerDialogListener再通,提供托管活动器具该界面。这就是我们下一步需要做的。另外请注意,我添加了一个静态便捷方法来创建一个带有ID的新TimePickerFragment。该值将被设置为片段的参数,确保它成为片段状态的一部分,因此您不必担心自己的配置更改 - 框架将为您执行此操作。

因此,让我们改变MainActivity来实现我们的自定义接口,并将其使用newInstance方法:

public class MainActivity extends FragmentActivity implements TimePickerFragment.TimePickerDialogListener { 

    private static final int START_TIME_PICKER_ID = 1; 
    private static final int END_TIME_PICKER_ID = 2; 

    public void InputStartTime(View v) { 
     // supply the appropriate id - I'm assuming you'll be adding an InputEndTime method somewhere that will then supply END_TIME_PICKER_ID 
     DialogFragment newFragment = TimePickerFragment.newInstance(START_TIME_PICKER_ID); 
     newFragment.show(getSupportFragmentManager(), "timePicker"); 
    } 

    @Override public void onTimeSet(int id, TimePicker view, int hourOfDay, int minute) { 
     Log.i("TimePicker", "Time picker set from id " + id + "!"); 

     // here you can compare the id value to figure out what picker this data came from 
    } 
} 

只是一个最后要注意的:我打这个直接进入我的浏览器,所以要知道任何明显的错别字。

+0

非常感谢!虽然@Override仍然产生了一个错误,删除它正常工作,谢谢你的解释,拯救了我的生活! – naz89 2013-04-10 07:12:03

+0

由于我在应用程序中有两个时间选择器,我怎样才能区分它们? 上面的代码检测onTimeSet为这些时间选择器之一,我如何扩展它以支持多个采集器? 你能否就此提供指导? 谢谢! – naz89 2013-04-10 07:18:03

+0

@ naz89:如果您构建的是Java 1.5,则在实现接口方法时,“@ Override”注释可能会产生错误。这在Java 1.6中发生了变化。支持多个采集器的方法不止一种:您可以在实例化对话框时提供某种'id',并设置您自己的包含此id的接口回调。或者,只需根据显示的选择器切换活动中的布尔值,并在'onTimeSet(...)'中检查其值。 – 2013-04-10 07:31:09

0

我让代码使用它。

​​
+0

非常感谢!虽然@Override仍然产生了一个错误,删除它正常工作,谢谢你的解释,拯救了我的生活! – naz89 2013-04-10 07:12:48

+0

由于我在应用程序中有两个时间选择器,我怎样才能区分它们? 上面的代码检测onTimeSet为这些时间选择器之一,我如何扩展它以支持多个采集器? 你能否就此提供指导? 谢谢! – naz89 2013-04-10 07:18:51