未调用TimePicker onTimeSet
问题内容:
我正在使用时间选择器让用户输入所需的时间来执行特定任务,我正在使用DialogFragment类,该类在支持库中可用,以便与旧版Android向后兼容。
这是我的代码,用于创建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方法,如果我尝试覆盖此方法,则会收到错误消息:“新TimePickerDialog.OnTimeSetListener(){}类型的方法onTimeSet(TimePicker,int,int)必须覆盖超类方法”
谁能告诉我问题是什么?我一直在努力解决问题,这让我感到非常沮丧!
问题答案:
我没有从日志中看到onTimeset方法
好吧,因为创建时TimePickerDialog
,您将片段提供为OnTimeSetListener
:
return new TimePickerDialog(getActivity(), this, hour, minute, false);
^
换句话说:您看不到log语句,因为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
如果托管活动实现了该接口,它将通过传递数据。这就是我们下一步需要做的。另外,请注意,我添加了一个静态便捷方法来创建一个TimePickerFragment
带有id
的新方法。该值将被设置为片段的参数,以确保它成为片段状态的一部分,因此您不必担心自己进行配置更改-框架将为您完成此操作。
因此,让我们进行更改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
}
}
最后一点:我直接在浏览器中输入了此信息,因此请注意任何明显的错别字。