【问题标题】:AlarmManager does not work when the app is closed. Why is that?当应用程序关闭时,AlarmManager 不起作用。这是为什么?
【发布时间】:2021-08-21 20:14:51
【问题描述】:

美好的一天, 我在我的 Android 应用程序中内置了一个计时器,它会在一定时间后发送一条消息。为此,我添加了一个带有待处理意图的 AlarmManager。当我打开应用程序时,一切正常。它也适用于锁定屏幕。但是当我关闭应用程序时,未决意图不再被激活,并且在给定时间没有出现任何消​​息。 这是我的警报管理器:

Intent notifyIntent = new Intent(getContext(), MyReceiver.class);
 alarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
        pendingIntent = PendingIntent.getBroadcast
                (getContext(), NOTIFICATION_ID, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);

//when the alarm gets activated:

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                            alarmManager.setExact(AlarmManager.RTC_WAKEUP,System.currentTimeMillis()+delta_time2, pendingIntent);

                        }
 else {
                            alarmManager.set(AlarmManager.RTC_WAKEUP,System.currentTimeMillis()+delta_time2, pendingIntent);

                        }

在 IntentService-Class 中(声明和调用通知的地方):


Intent notifyIntent = new Intent(this, BigTextMainActivity.class);

      
        notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

        PendingIntent notifyPendingIntent =
                PendingIntent.getActivity(
                        this,
                        0,
                        notifyIntent,
                        PendingIntent.FLAG_UPDATE_CURRENT
                );



       
        Intent snoozeIntent = new Intent(this, BigTextIntentService.class);
        snoozeIntent.setAction(BigTextIntentService.ACTION_SNOOZE);

        PendingIntent snoozePendingIntent = PendingIntent.getService(this, 0, snoozeIntent, 0);
        NotificationCompat.Action snoozeAction =
                new NotificationCompat.Action.Builder(
                        R.drawable.ic_alarm_white_48dp,
                        "Snooze",
                        snoozePendingIntent)
                        .build();

        Intent dismissIntent = new Intent(this, BigTextIntentService.class);
        dismissIntent.setAction(BigTextIntentService.ACTION_DISMISS);

        PendingIntent dismissPendingIntent = PendingIntent.getService(this, 0, dismissIntent, 0);
        NotificationCompat.Action dismissAction =
                new NotificationCompat.Action.Builder(
                        R.drawable.ic_cancel_white_48dp,
                        "Dismiss",
                        dismissPendingIntent)
                        .build();

        NotificationCompat.Builder notificationCompatBuilder =
                new NotificationCompat.Builder(
                        getApplicationContext(), notificationChannelId);

        GlobalNotificationBuilder.setNotificationCompatBuilderInstance(notificationCompatBuilder);

        Notification notification = notificationCompatBuilder
                .setStyle(bigTextStyle)
                .setContentTitle(bigTextStyleReminderAppData.getContentTitle())
                .setContentText(bigTextStyleReminderAppData.getContentText())
                .setSmallIcon(R.drawable.ic_launcher)
                .setLargeIcon(BitmapFactory.decodeResource(
                        getResources(),
                        R.drawable.ic_alarm_white_48dp))
                .setContentIntent(notifyPendingIntent)
                .setDefaults(NotificationCompat.DEFAULT_ALL)
    
                .setColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary))


                .setCategory(Notification.CATEGORY_REMINDER)

                .setPriority(bigTextStyleReminderAppData.getPriority())

                .setVisibility(bigTextStyleReminderAppData.getChannelLockscreenVisibility())

             
                .addAction(snoozeAction)
                .addAction(dismissAction)

                .build();
//I am not quite shure, if I declared the foregroundservice for the notification at the right place
 
        startForeground(NOTIFICATION_ID, notification);
        mNotificationManagerCompat.notify(NOTIFICATION_ID, notification);
        Vibrator vibrator = (Vibrator) getApplication().getSystemService(Context.VIBRATOR_SERVICE);
        vibrator.vibrate(2 * 1000);

这些是我的权限:

<uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-permission android:name="android.permission.VIBRATE"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

感谢您的帮助! (顺便说一句,如果这个问题很愚蠢或者是因为我没有真正处理这个话题,只是想快速为我的应用程序设置警报,请提前抱歉)

【问题讨论】:

  • 你在什么设备上测试这个?它运行的是什么版本的 Android?
  • AlarmManager 将在其关闭时触发MyReceiver。您是否添加了日志记录以查看是否发生这种情况? MyReceiver.onReceive() 的代码在哪里?
  • 我在运行 Android 10 的设备上对其进行了测试。我检查了 logcat 和消息“java.lang.RuntimeException: Unable to start receiver com.example.myapplication.ui.dashboard.MyReceiver : java.lang.IllegalStateException: 不允许启动服务 Intent { cmp=com.example.myapplication/.ui.dashboard.MyNewIntentService }: 应用程序在后台 uid UidRecord{1ea9ce7 u0a353 RCVR 空闲更改:idle|uncached procs:1 seq (0,0,0)}”出现。在模拟器设备(在 Android 11 上)上一切正常。
  • MyReceiver.onReceive() 的代码就是:“public class MyReceiver extends BroadcastReceiver { public MyReceiver() { } @Override public void onReceive(Context context, Intent intent) { Intent intent1 = new Intent (context, MyNewIntentService.class); context.startService(intent1); } }"
  • 我必须纠正自己:它也不适用于 Android 模拟器。出现相同的消息,说明我的应用程序在后台。为了让我的应用保持在前台,我需要进行哪些更改?

标签: android permissions alarmmanager android-pendingintent


【解决方案1】:

根据您的 cmets,警报似乎正在触发,但您的 BroadcastReceiver 在尝试启动您的 Service 时失败。最可能的原因是您的设备对后台处理有额外的限制。一些设备,主要是低端设备和中国制造商,对允许“在后台”运行的应用程序有限制。如果您的应用不在允许应用的“白名单”中,Android 将不允许应用的组件在后台启动。

请参阅https://developer.android.com/about/versions/oreo/background 以了解背景Service 限制,并参阅https://stackoverflow.com/a/45482394/769265 作为答案示例,其中我讨论了某些制造商限制后台处理的问题。


注意: 由于您无法在 Android 8 及更高版本上启动后台 Service(由于限制),您可以将 Service 启动为前台 Service,如下所示:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    context.startForegroundService(intent)
} else {
    context.startService(intent)
}

【讨论】:

  • 非常感谢,ForegroundService 现在可以使用了!
  • 好吧,除了我的应用程序总是在您保持打开状态并且警报已过期时关闭。通知仍在发送,但应用程序已关闭。如果你还有时间,你能告诉我为什么吗? (在 Logcat 中,消息:“android.app.RemoteServiceException: Context.startForegroundService() 没有调用 Service.startForeground(): ServiceRecord{7fae484 u0 com.example.myapplication/.ui.dashboard.MyNewIntentService}”被发送)
  • 错误消息几乎可以告诉您问题所在。您需要阅读有关前台Services 的文档。如果你的Service 作为前台运行Service,它需要调用startForeground()。显然,您还没有将此添加到您的 Service 代码中。见developer.android.com/guide/components/foreground-services
  • 现在我遇到了问题,通知只是在短时间内从屏幕上消失。我不知道,我改变了什么,但你能告诉我,为什么会发生这种情况吗?
  • 不,抱歉。查看 logcat 或尝试追溯您的更改。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-09
  • 1970-01-01
  • 1970-01-01
  • 2017-12-13
  • 2013-12-01
相关资源
最近更新 更多