Java 未调用时间集上的时间选择器

Java 未调用时间集上的时间选择器,java,android,datepicker,overriding,timepicker,Java,Android,Datepicker,Overriding,Timepicker,我使用一个时间选择器让用户输入他想要的时间来完成一个特定的任务,我使用支持库中的DialogFragment类来向后兼容旧的Android版本 下面是我创建TimePickerFragment类的代码,该类在一个单独的文件中创建,取自: 主要活动: package com.calls.only; import java.util.Calendar; import java.util.TimeZone; import android.os.Bundle; import android.app.

我使用一个时间选择器让用户输入他想要的时间来完成一个特定的任务,我使用支持库中的DialogFragment类来向后兼容旧的Android版本

下面是我创建TimePickerFragment类的代码,该类在一个单独的文件中创建,取自:

主要活动:

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方法,如果尝试重写此方法,则会出现错误: 类型为new TimePickerDialog.OnTimeSetListener(){}的方法onTimeSet(TimePicker,int,int)必须重写超类方法

谁能告诉我是什么问题吗? 我一直在努力想办法,但这让我太沮丧了

从日志中可以看出,没有调用onTimeset方法

这是因为当您创建
TimePickerDialog
时,您将片段作为
OnTimeSetListener
提供:

return new TimePickerDialog(getActivity(), this, hour, minute, false);
                                             ^
换句话说:您没有看到log语句,因为活动中的
mTimeSetListener
变量从未被设置为您在片段中创建的对话框的侦听器

您可以通过将片段附加到
MainActivity
的活动强制转换,或者,如果您更喜欢可重用的内容,则通过接口将其回调,从而轻松解决此问题。在这种情况下,您可以重用
OnTimeSetListener
接口,但也可以设置自己的接口,例如,将
日历
对象传递回活动,而不是原始的小时/分钟值

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

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!");
    }
}

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

然而,我更愿意做的是,通过向每个选择器提供一个id,能够识别
onTimeSet(…)
中返回的结果的来源。然后,该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
    }
}
最后一点注意:我是直接在浏览器中输入的,所以请注意任何明显的打字错误

从日志中可以看出,没有调用onTimeset方法

这是因为当您创建
TimePickerDialog
时,您将片段作为
OnTimeSetListener
提供:

return new TimePickerDialog(getActivity(), this, hour, minute, false);
                                             ^
换句话说:您没有看到log语句,因为活动中的
mTimeSetListener
变量从未被设置为您在片段中创建的对话框的侦听器

您可以通过将片段附加到
MainActivity
的活动强制转换,或者,如果您更喜欢可重用的内容,则通过接口将其回调,从而轻松解决此问题。在这种情况下,您可以重用
OnTimeSetListener
接口,但也可以设置自己的接口,例如,将
日历
对象传递回活动,而不是原始的小时/分钟值

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

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!");
    }
}

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

然而,我更愿意做的是,通过向每个选择器提供一个id,能够识别
onTimeSet(…)
中返回的结果的来源。然后,该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
方法