在广播接收器中使用 setExact() 重复

Posted

技术标签:

【中文标题】在广播接收器中使用 setExact() 重复【英文标题】:Using setExact() in broadcast receiver to repeat 【发布时间】:2018-10-20 19:36:09 【问题描述】:

场景: 生产线工人每隔一定时间进行检查。在我的应用程序上,用户将此时间间隔输入到文本框中。有日期和时间选择器,以便用户可以选择流程何时开始。我正试图在下次检查到期前 5 分钟发出警报。

例如: 进程从 2.30 开始。用户每隔 20 分钟输入一次。因此,下一次检查应在 2.50 到期。警报应在 2.45 响起。然后将重复此过程,因此下一次检查将是 3.10,警报应在 3.05 响起。

这是我的代码:

 MainActivity.calculate();
        commencedTime = new Date();
        mTime = Calendar.getInstance();
        mTime.setTime(alarmTime);
        timeCommenced = trimSecsAndMillisecs(mTime).getTimeInMillis();

        currentTime = new Date();
        currentTime.getTime();

        alertDialogBuilder = new AlertDialog.Builder(MainActivity.this);
        //set alert
        alertDialogBuilder
                .setTitle("IP Check frequency: " + time.getText() + " minutes")
                .setMessage("Processing commenced at \n" + startTime.getText())
                .setCancelable(false)
                .setPositiveButton("Yes", new DialogInterface.OnClickListener() 
                    @Override
                    public void onClick(DialogInterface dialog, int which) 

                        if (currentTime.after(alarmTime)) 
                            Toast.makeText(MainActivity.this, "Missed first alert", Toast.LENGTH_LONG).show();
                        

                        i = Integer.parseInt(time.getText().toString());
                        long scTime2 = ((i * 60 * 1000)); //TIME ENTERED IN MILLISECONDS

                        intent1 = new Intent(MainActivity.this, MyBroadcastReceiver.class);
                        intent1.putExtra("timeEntered", scTime2);
                        intent1.putExtra("timeCommenced", timeCommenced);
                        sendBroadcast(intent1);

                        pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0, intent1, PendingIntent.FLAG_UPDATE_CURRENT);

                        manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
                        manager.setExact(AlarmManager.RTC_WAKEUP, timeCommenced, pendingIntent);

                        Toast.makeText(MainActivity.this, "Alert Set", Toast.LENGTH_SHORT).show();
                        stopped.setVisibility(View.VISIBLE);
                        commenced1.setVisibility(View.GONE);

                        //Change editText to TextView
                        time.setVisibility(View.GONE);
                        timeText.setVisibility(View.VISIBLE);
                        timeText.setText(time.getText().toString());
                        processingText.setText(R.string.processing_commenced);

                    
                )
                .setNegativeButton("Cancel", new DialogInterface.OnClickListener() 
                    @Override
                    public void onClick(DialogInterface dialog, int which) 
                        dialog.cancel();
                    
                );
        alertDialog = alertDialogBuilder.create();
        alertDialog.show();

    

广播接收器:

@Override
public void onReceive(Context context, Intent intent) 
    // Vibrate the mobile phone
    vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
    long[] pattern = 0, 10000, 3, 10000;
    vibrator.vibrate(pattern, -1); // vibration for 20 seconds

    //create as instance of the media player
    mediaPlayer = MediaPlayer.create(context, R.raw.alarm_sound);
    mediaPlayer.start();

   createNotification(context, "AlmaIPC", "IP check is due", "Alert");

    AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
    Intent intent2 = new Intent(context, MainActivity.class);
    PendingIntent pi2 = PendingIntent.getActivity(context, 0, intent2, 0);

    Long timeEntered =intent.getLongExtra("timeEntered", 0);


    AlarmManager.AlarmClockInfo ac=
            new AlarmManager.AlarmClockInfo(System.currentTimeMillis() + timeEntered,
                    pi2);

    manager.setAlarmClock(ac, pi);



我在 setExact() 参数中的 timecommenced 变量正在正确调试它应该在什么时间触发警报。

在我的广播接收器中,我试图通过这个值并添加用户输入的时间间隔,这将保持警报时间的完整。例如2.45 然后 3.05。

由于某种原因,我单击“处理开始”而不是在timecommenced 状态时发出警报,它立即触发。然后,警报时间完全关闭,它有自己的想法。

谁能看到我做错了什么或给我一些建议?

谢谢!

【问题讨论】:

顾名思义,“setExact”在 android 6+ [API 21+] 上不起作用。它会受到打瞌睡的限制~当设备不充电且屏幕关闭时。要发出可靠的面向用户的警报,应使用 AlarmManager 的“setAlarmClock”方法。 此外,当初始时间设置过去时,警报通常会立即触发。从代码中,我想您已经知道 RTC_WAKEUP 是基于 System.currentTimeMillis() 的。这个工具EPOCH Converter 可用于将时间从毫秒转换为人类时间。 @Elletlar 感谢您的回复,好的,我应该尝试 setAlarmClock 方法吗?并且我是否在广播接收器中正确编码了“重复”?再次感谢 对于 Android 5 及以下设备,必须使用 setExact。对于 Android 6 及更高版本,应使用 setAlarmClock。因此,除非最小 API 设置为 21,否则您可能需要同时实现两者。您是否根据手机上的时钟时间检查了 EPOCH 转换器中的重复时间? 嗨@Elletlar。第一个警报有效,所以我在那里进行了测试,当我的支票在 9.12 到期时,它在 9.07 发出警报,所以这是正确的。唯一的问题是我现在如何在广播接收器中重复这个? 【参考方案1】:

顾名思义,“setExact”在 Android 6+ [API 21+] 上不起作用。在设备不充电且屏幕关闭时,大致会受到打瞌睡的限制。 [注意:从 Android 7 开始,问题更加严重,因为它具有更激进的 Doze 形式]

要发出可靠的面向用户的警报,应使用 AlarmManager 的“setAlarmClock”方法。

AlarmManager am =
  (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent1 = new Intent(context, myReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
Intent intent2 = new Intent(context, myActivity.class);
PendingIntent pi2 = PendingIntent.getActivity(context, 0, i2, 0);

AlarmManager.AlarmClockInfo ac=
  new AlarmManager.AlarmClockInfo(System.currentTimeMillis() + DELAY,
    pi2);

am.setAlarmClock(ac, pi);

来自文档:

setAlarmClock 在 API 级别 21 中添加

void setAlarmClock (AlarmManager.AlarmClockInfo info, 
            PendingIntent operation)

安排一个代表闹钟的闹钟,它会在闹钟响起时通知用户。预期当此警报触发时,应用程序将进一步唤醒设备以告知用户有关警报的信息——打开屏幕、播放声音、振动等。因此,系统通常也会使用该信息在此处提供以告知用户此即将到来的警报(如果适用)。

由于这种警报的性质,类似于 setExactAndAllowWhileIdle(int, long, PendingIntent),即使系统处于低功耗空闲(又名打盹)模式,这些警报也将被允许触发

Alarm Manager Docs

要设置多个警报,请在 PendingIntent 中为每个警报设置一个唯一的“requestCode”:

 static PendingIntent   getBroadcast(Context context, int requestCode, Intent intent, int flags)

【讨论】:

我会试试看的!这是可重复的吗? 我让这个工作了一段时间,然后当我去演示它时,它根本没有工作。 (演示标准)我只是想知道您是否知道原因或经历过这种情况?

以上是关于在广播接收器中使用 setExact() 重复的主要内容,如果未能解决你的问题,请参考以下文章

在广播接收器中调用活动字符串方法[重复]

在android中卸载应用程序时调用广播接收器[重复]

在现有使用广播接收器的应用程序之后,有没有办法让重复警报工作?

用于应用权限的 Android 广播接收器

在android的广播接收器中检测日变化事件

Android深入四大组件广播的注册发送和接收过程