.NET MAUI中通过BroadcastReceiver无法停止Android服务的问题排查
问题分析与修复方案
核心问题
- 前台服务停止方式错误:你的
LocationService是通过StartForeground启动的前台服务,直接调用StopService只会移除通知,但不会正确触发服务内的清理逻辑,系统也不会立即销毁服务。 - 错误的资源清理位置:你重写了
StopService方法来处理资源释放,但Android中服务停止时的标准清理入口是OnDestroy方法,而非StopService。 - 未初始化的
CancellationTokenSource:构造函数中未实例化token,会导致OnDestroy中出现空引用异常。
具体修复步骤
1. 修复CancellationTokenSource初始化
在LocationService构造函数中补充初始化代码:
public LocationService() { mediaPlayer = new MediaPlayer(); timer = new Timer(3000); timer.Elapsed += VibrateTimer; token = new CancellationTokenSource(); // 补充初始化 }
2. 调整BroadcastReceiver的停止逻辑
修改ExampleBroadcast,通过发送带特定Action的Intent让服务自行处理停止:
public override void OnReceive(Context context, Intent intent) { if(intent.Action == "deneme") { Debug.WriteLine(intent.Action); Intent serviceIntent = new Intent(context, typeof(LocationService)); serviceIntent.SetAction("STOP_SERVICE"); // 添加停止指令Action context.StartService(serviceIntent); } }
3. 在服务中处理停止指令并迁移资源清理逻辑
修改LocationService的OnStartCommand方法处理停止Action,同时将资源清理逻辑移到OnDestroy:
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId) { // 处理停止指令 if (intent.Action == "STOP_SERVICE") { StopForeground(true); // 移除前台通知 StopSelf(); // 主动停止服务 return StartCommandResult.NotSticky; } // 原有的服务启动逻辑 var index = intent.GetIntExtra("alarm", -1); Debug.WriteLine("Start: " + index + " " + intent.Action); var json = File.ReadAllText(FileSystem.Current.AppDataDirectory + "/alarm.json"); var alarms = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Alarm>>(json); var alarm = alarms[index]; Title = alarm.AlarmName; Description = $"{0}m sonra alarm çalacak!"; mediaPlayer.SetDataSource(alarm.SoundPath); mediaPlayer.Prepare(); mediaPlayer.Start(); timer.Start(); StartForegroundService(); return StartCommandResult.Sticky; } // 移除原有的StopService重写,改用OnDestroy处理清理 public override void OnDestroy() { base.OnDestroy(); // 清理MediaPlayer if (mediaPlayer != null) { mediaPlayer.Stop(); mediaPlayer.Release(); // 必须释放资源避免内存泄漏 mediaPlayer.Dispose(); } // 取消振动 Vibration.Default.Cancel(); // 清理Timer if (timer != null) { timer.Stop(); timer.Dispose(); } // 取消CancellationToken token?.Cancel(); token?.Dispose(); }
4. 适配Android 12+的PendingIntent Flags
修改StartForegroundService中PendingIntent的创建,添加Immutable标志(适配Android 12及以上版本):
var pendingIntent = PendingIntent.GetBroadcast(this, 0, intent, PendingIntentFlags.UpdateCurrent | PendingIntentFlags.Immutable);
修复逻辑说明
- 前台服务必须先调用
StopForeground(true)移除前台状态,再调用StopSelf()才能让系统正确销毁服务并触发OnDestroy。 - 将资源清理逻辑放在
OnDestroy是Android服务的标准做法,确保服务无论以何种方式停止,资源都能被正确释放。 - 通过发送Action指令让服务自行停止,避免跨组件调用的权限或Intent匹配问题。
内容的提问来源于stack exchange,提问作者Metehan Ö.
相关产品推荐
相关产品推荐

