本文介绍了TimePicker onTimeSet 未被调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm using a time picker to let the user enter his desired time to do a specific task, I'm using the DialogFragment class that's available in the support library for backward compatibility with older Android versions.

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

Here is my code to create the TimePickerFragment class, created in a seperate file, taken from: 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 方法,如果我尝试覆盖此方法,则会收到错误消息:new TimePickerDialog.OnTimeSetListener(){} 类型的 onTimeSet(TimePicker, int, int) 方法必须覆盖超类方法"

the onTimeset method is not being called as I can see from the log, if I try to override this method, I get the error:"The method onTimeSet(TimePicker, int, int) of type new TimePickerDialog.OnTimeSetListener(){} must override a superclass method"

谁能告诉我是什么问题?我一直在想办法解决这个问题,结果让我很沮丧!

can anyone tell me what the problem is?I've been trying to figure it out and it left me with too much frustration!

推荐答案

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

Well, that's because when you create the TimePickerDialog, you supply the fragment as OnTimeSetListener:

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

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

In other words: you're not seeing the log statement because the mTimeSetListener variable in your activity never gets set as listener to the dialog you create in the fragment.

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

You can easily fix this by either casting the activity the fragment is attached to to your MainActivity, or, if you prefer something more reusable, have it callback through an interface. In this case you could reuse the OnTimeSetListener interface, but you could also set up your own that, for instance, passes on a Calendar object back to the activity rather than the raw hour/minute values.

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

In it's most basic form, it would look somewhat like this:

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 实现相同的接口,而不是使用匿名内部类:

And then have your MainActivity implement that same interface, in stead of using an anonymous innerclass:

public class MainActivity extends FragmentActivity implements TimePickerDialog.OnTimeSetListener {

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

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


Update: As mentioned in the comments, to enabled support for multiple pickers, you have several options. One is to keep track of what dialog is displayed in the hosting activity; a boolean would do fine if you only need to differentiate between two pickers, otherwise an enum would be an appropriate way to implement more than two states. You'll want to make sure that this piece of information is retained during configuration changes though...

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

However, what I'd prefer is to do, is to be able to identify the source of the result returned in onTimeSet(...) by supplying an id to every picker. That id is then included in the result so that we can tell where it came from. I'll outline the general idea below:

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.这个值将被设置为片段的参数,确保它成为片段状态的一部分,所以你不必担心自己的配置更改 - 框架会为你做这些.

What we've changed above is to have the dialog itself be registered as OnTimeSetListener, for which it will then pass on data through the TimePickerDialogListener, provided the hosting activity implements that interface. So that's what we need to do in the next step. Also, note that I've added a static convenience method to create a new TimePickerFragment that takes an id. This value will be set as argument to the fragment, ensuring that it becomes part of the fragment's state, so you don't have to worry about configuration changes yourself - the framework will do that for you.

那么让我们改变 MainActivity 来实现我们的自定义接口,并让它使用 newInstance 方法:

So let's change MainActivity to implement our custom interface, and have it use the newInstance method:

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
    }
}

最后一点:我是直接在浏览器中输入的,所以请注意任何明显的拼写错误.

Just one final note: I typed this directly into my browser, so be aware of any obvious typos.

这篇关于TimePicker onTimeSet 未被调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-24 04:23