应用关闭时,警报未唤醒我的服务

时间:2018-07-24 19:23:52

标签: android alarmmanager android-alarms repeatingalarm

我希望每n分钟启动一次服务。此方法有效,但仅在应用程序正在运行时(在屏幕上处于活动状态或最小化处于活动状态)。当我关闭它时(点击右下角的按钮并滑动到侧面),该服务停止启动。

设置闹钟(在--restart中):

MainActivity.onStart

AndroidManifest.xml:

Intent startServiceIntent = new Intent(this, LogSyncService.class);
PendingIntent alarmIntent = PendingIntent.getService(this, 0, startServiceIntent, 0);

AlarmManager alarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
alarmManager.setInexactRepeating(
    AlarmManager.ELAPSED_REALTIME_WAKEUP,
    SystemClock.elapsedRealtime(),
    5 * 1000, // low for testing purposes
    alarmIntent);

通过查看警报转储(<service android:name=".LogSyncService" android:description="@string/logSyncService_description" android:exported="false"/> ),我可以清楚地看到,即使关闭了该应用程序(唤醒次数在增加),该警报仍然有效,但由于该服务没有被调用是打开应用程序的时间。当我手动重新打开应用程序时,一切都可以正常工作。

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

警报

您应该阅读Doze and Standby如何影响装有Android 6.0及更高版本的设备上的警报。当电话进入打ze状态时,所有警报和后台作业都将停止,直到进入维护期为止。setAndAllowWhileIdle()setExactAndAllowWhileIdle()会在这些状态下运行新的警报 因此,基本上,您应该创建一个新方法,在该方法中,您将根据平台版本调用不同的警报方法:

    public void setExactAlarm(int alarmType, long triggerTime, PendingIntent operation) {

    AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

    if (alarmManager != null) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            alarmManager.setExactAndAllowWhileIdle(alarmType, triggerTime, operation);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            alarmManager.setExact(alarmType, triggerTime, operation);
        } else {
            alarmManager.set(alarmType, triggerTime, operation);
        }
    }
}

请注意在休眠状态下如何推迟警报:

  

在正常系统操作下,它不会再发送这些警报   大约每分钟(此时每个此类待处理的警报是   派遣);在低功率空闲模式下,此持续时间可能为   明显更长,例如15分钟。


服务

最新的SDK API中的内容已更改。如果您在平台26+上运行应用程序,则对后台服务有限制。

  

如果您的应用程序的目标是API级别26或更高级别,则除非应用程序本身位于前台,否则系统会限制使用或创建后台服务。如果应用程序需要创建前台服务,则该应用程序应调用startForegroundService()。该方法创建了后台服务,但是该方法向系统发出信号,表明该服务会将自己提升到前台。创建服务后,服务必须在五秒钟内调用其startForeground()方法。

因此,如果您需要某些后台服务,现在必须通过通知通知用户某些服务在后台执行。

这是警报触发时广播接收器的一些示例代码:

Intent service= new Intent(this, ExampleService.class);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
            context.startForegroundService(service);
        else
            context.startService(intent);

最后,在onStartCommand()中的服务内部,您必须再次检查SDK版本,如果版本为26+,则应调用startForeground();

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    Notification notification = new NotificationCompat.Builder(context, channalId);
    startForeground(NOTIFICATION_ID, notification);
}