You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AlarmManager仅触发一次且BroadcastReceiver未调用Service问题求助

解决Alarm仅触发一次且服务未被调用的问题

看起来你碰到了两个核心问题:Alarm只执行一次,以及高版本Android中服务无法被后台启动。我来一步步帮你修复这些问题:

1. 修复Alarm仅触发一次的问题

你当前用的AlarmManager.Set()是一次性触发的API,要实现每小时重复执行,得换成重复触发的方法:

适配多版本的重复Alarm设置

替换MainActivity里的Alarm配置代码:

this.context = this;
Intent alarmIntent = new Intent(this, typeof(AlarmReceiver));
// 若需要区分多个PendingIntent,requestCode要设为唯一值
var pending = PendingIntent.GetBroadcast(this, 0, alarmIntent, PendingIntentFlags.UpdateCurrent | PendingIntentFlags.Immutable);
var alarmManager = GetSystemService(AlarmService).JavaCast<AlarmManager>();

// 推荐使用不精确重复(更省电,API 19+支持)
alarmManager.SetInexactRepeating(
    AlarmType.ElapsedRealtimeWakeup, // 用Wakeup确保设备休眠时也能触发
    SystemClock.ElapsedRealtime() + 5 * 1000, // 首次延迟5秒启动
    AlarmManager.IntervalHourly, // 每小时重复一次
    pending
);

// 若需要精确重复(仅API 19以前有效,API 19后会被系统调整为不精确)
// alarmManager.SetRepeating(
//     AlarmType.ElapsedRealtimeWakeup,
//     SystemClock.ElapsedRealtime() + 5 * 1000,
//     60 * 60 * 1000, // 3600000毫秒 = 1小时
//     pending
// );

注意点:

  • 用ElapsedRealtimeWakeup而非ElapsedRealtime,确保设备休眠时Alarm也能触发
  • 添加PendingIntentFlags.Immutable(API 31+强制要求),避免PendingIntent被意外篡改

2. 修复服务未被调用的问题

从Android 8.0(API 26)开始,系统严格限制后台启动服务的行为,直接调用StartService()会抛出IllegalStateException,需要改用前台服务:

修改AlarmReceiver的服务启动逻辑

[BroadcastReceiver]
[IntentFilter(new[] { Intent.ActionBootCompleted })] // 可选:添加开机自启支持
public class AlarmReceiver : BroadcastReceiver {
    public override void OnReceive(Context context, Intent intent) {
        Toast.MakeText(context, "Received intent!", ToastLength.Short).Show();
        Intent not = new Intent(context, typeof(Services.NotifcationService));
        
        if (Build.VERSION.SdkInt >= BuildVersionCodes.O) {
            // API 26+必须使用StartForegroundService启动服务
            context.StartForegroundService(not);
        } else {
            // 低版本用StartService
            context.StartService(not);
        }
    }
}

将NotificationService改造为前台服务

API 26+要求前台服务必须显示通知,否则系统会在几秒内终止服务,修改你的服务代码:

using System;
using Android.App;
using Android.Content;
using Android.OS;
namespace example.Services {
    [Service(Label = "NotificationService")]
    [IntentFilter(new String[] { "com.example.NotificationService" })]
    public class NotificationService : Service {
        IBinder binder;
        private const int NOTIFICATION_ID = 1;
        private const string CHANNEL_ID = "ForegroundServiceChannel";

        public override void OnCreate() {
            base.OnCreate();
            // 创建通知渠道(API 26+必需)
            CreateNotificationChannel();
        }

        public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId) {
            // 构建前台通知
            Notification notification = new Notification.Builder(this, CHANNEL_ID)
                .SetSmallIcon(Resource.Drawable.logoArrow)
                .SetContentTitle("Foreground Service Running")
                .SetContentText("Your notification service is active")
                .SetPriority(NotificationPriority.High)
                .Build();

            // 将服务设为前台服务
            StartForeground(NOTIFICATION_ID, notification);

            // 执行你的业务逻辑:发送本地通知
            SendLocalNotification();

            // 返回Sticky确保服务被杀死后可重启(根据需求调整)
            return StartCommandResult.Sticky;
        }

        private void SendLocalNotification() {
            var notificationManager = (NotificationManager)GetSystemService(NotificationService);
            Notification.Builder notifyBuilder = new Notification.Builder(this, CHANNEL_ID)
                .SetSmallIcon(Resource.Drawable.logoArrow)
                .SetContentTitle("Sample Notification")
                .SetContentText("Hello World! This is my first notification")
                .SetPriority(NotificationPriority.Default)
                .Build();
            notificationManager.Notify(2, notifyBuilder.Build()); // 用不同ID避免覆盖前台通知
        }

        private void CreateNotificationChannel() {
            if (Build.VERSION.SdkInt >= BuildVersionCodes.O) {
                var channel = new NotificationChannel(CHANNEL_ID, "Foreground Service Channel", NotificationImportance.Default) {
                    Description = "Channel for foreground service notifications"
                };
                var notificationManager = (NotificationManager)GetSystemService(NotificationService);
                notificationManager.CreateNotificationChannel(channel);
            }
        }

        public override IBinder OnBind(Intent intent) {
            binder = new NotificationServiceBinder(this);
            return binder;
        }
    }

    public class NotificationServiceBinder : Binder {
        readonly NotificationService service;
        public NotificationServiceBinder(NotificationService service) {
            this.service = service;
        }
        public NotificationService GetNotificationService() {
            return service;
        }
    }
}

3. 检查Manifest配置

确保已添加必要权限和组件声明:

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

<application ...>
    <receiver android:name=".AlarmReceiver" />
    <service android:name=".Services.NotificationService" />
</application>

额外提示

  • Android 12(API 31)及以上,若需要精确Alarm,需申请SCHEDULE_EXACT_ALARM权限并动态请求
  • 长期重复任务更推荐使用WorkManager,它能更好适配系统省电策略,尤其是Android 12+环境

内容的提问来源于stack exchange,提问作者Gurpreet Bhopal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:23:21