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

.NET MAUI中通过BroadcastReceiver无法停止Android服务的问题排查

问题分析与修复方案

核心问题

  1. 前台服务停止方式错误:你的LocationService是通过StartForeground启动的前台服务,直接调用StopService只会移除通知,但不会正确触发服务内的清理逻辑,系统也不会立即销毁服务。
  2. 错误的资源清理位置:你重写了StopService方法来处理资源释放,但Android中服务停止时的标准清理入口是OnDestroy方法,而非StopService。
  3. 未初始化的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 Ö.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 07:07:11