在获得时间选择器和当前时间之间的时间延迟后使用 postDelayed 安排任务

Scheduling a task using postDelayed after getting time delay between time picker and current time

我在我的片段中写了一段代码,它将在用户在 Time Picker 上选择的特定时间显示 Toast 消息。时间延迟是通过从时间选择器时间(以毫秒为单位)中减去当前时间(以毫秒为单位)来计算的。 但是,没有显示 toast 消息,我也没有在 logcat 中收到任何错误。 这是代码片段:

public class ManualControlsFragment extends Fragment {
    private TimePicker tp;
    private Calendar calendar;
    Handler mHandler;
    private Runnable scheduledTask;
    long pickedTimeInMillis=0;

   //some fragment methods

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        tp = (TimePicker) view.findViewById(R.id.lightTimePickerStart);
        tp.setIs24HourView(true);
        calendar = Calendar.getInstance();

        //get time picked in milliseconds
        tp.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {
            @Override
            public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
                calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
                calendar.set(Calendar.MINUTE, minute);

                pickedTimeInMillis= calendar.getTimeInMillis();
            }
        });

        //Calendar instance to get current time
        Calendar cal = Calendar.getInstance();

        //get the difference to get the delay
        long timeDifference = pickedTimeInMillis - cal.getTimeInMillis();

        mHandler = new Handler();
        mHandler.postDelayed(scheduledTask, timeDifference);

        scheduledTask = new Runnable() {
            String text= "Bulb is now on";
            @Override
            public void run() {
                Toast.makeText(
                        getActivity(), text, Toast.LENGTH_LONG).show();
            }
        };

        return view;
    }

阅读这里的评论和答案后,我将代码编辑为:

 getActivity().runOnUiThread(new Runnable() {
        @Override
        public void run() {
            new Handler().postDelayed(new Runnable() {
                String text= "Bulb is now on";
                @Override
                public void run() {
                    //Do something after 1 second
                    Toast.makeText(getActivity().getApplicationContext(), text, Toast.LENGTH_LONG).show();
                }
            }, timeDifference);
        }
    });

但是,这使得吐司仅在我启动应用程序时显示(当我启动它时,时间选择器上的时间是当前时间,这就是我认为它随后显示该吐司的原因)。当我在应用程序 运行 的时间选择器上设置时间时,不显示吐司。

您是另一个线程上的 运行 Toast,但您只能从主线程更新 UI。例如,尝试更新 Runnable run() 中的代码以使用 runOnUiThread() 方法。

正如我在评论中所说,您需要更改代码中的顺序以使其按您的意愿执行。

首先,在 Handler 的 postDelayed() 方法中使用它之前 初始化 scheduledTask,否则您所做的只是 post 一个空的 Runnable。您的代码应该是:

scheduledTask = new Runnable() {
        String text= "Bulb is now on";
        @Override
        public void run() {
            Toast.makeText(
                    getActivity(), text, Toast.LENGTH_LONG).show();
        }
};
mHandler.postDelayed(scheduledTask, timeDifference);

其次,下面的代码(在 onCreateView() 方法内部):

Calendar cal = Calendar.getInstance();
//get the difference to get the delay
long timeDifference = pickedTimeInMillis - cal.getTimeInMillis();

将立即触发一个 Toast,因为 pickedTimeInMillis 将为 0,因此时差将为负,这将四舍五入为 0(因此立即执行)。如果你想要这个,请保留这部分代码,否则将其从 onCreateView() 中删除。

第三,您需要 post Runnable 当用户更改时间 并调用 OnTimeChangedListener 侦听器时。所以监听器中的代码应该是:

@Override
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
            calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
            calendar.set(Calendar.MINUTE, minute);
            pickedTimeInMillis= calendar.getTimeInMillis();
            // at this point get the current time 
            Calendar cal = Calendar.getInstance();
            // now calculate the difference as the user actually selected a time
            long timeDifference = pickedTimeInMillis - cal.getTimeInMillis();
            // register the Runnable to run
            mHandler.postDelayed(scheduledTask, timeDifference);
        }

此外,不需要 运行OnUiThread(),因为您声明的处理程序将 运行 在主线程上。