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

Xamarin.Android前台服务重复创建线程 如何终止旧实例的线程

问题根因

Android前台服务一旦启动成功处于运行状态,后续重复调用StartService()不会创建新的服务实例,仅会触发OnStartCommand回调。你当前的代码每次接收到START_SERVICE动作时,都会无判断执行RegisterNotification()方法,该方法中每次都会新建工作线程赋值给refrescar变量,旧线程的循环逻辑没有终止标识,会持续在后台运行,最终导致每次重启应用都会多一个拉取数据的线程。

修复方案

按以下步骤修改Servicio类即可解决重复创建线程的问题:

  1. 新增类级别的线程运行状态标识、线程终止控制变量,避免重复创建线程,同时替代不安全的Thread.Abort()方法
  2. 执行线程创建逻辑前先判断工作线程是否已存活,存活则直接跳过创建逻辑
  3. 避免重复执行前台服务通知注册逻辑

修改后的核心代码示例

[Service(ForegroundServiceType = Android.Content.PM.ForegroundService.TypeDataSync)]
public class Servicio : Service, IServicio
{
    Uri link = new Uri(new Url().Dir + "/estado_alarma.php");
    Thread refrescar;
    // 新增控制变量
    private bool _isThreadRunning = false;
    private bool _stopThreadFlag = false;
    // 标记通知是否已经注册,避免重复初始化
    private bool _notificationRegistered = false;

    public override IBinder OnBind(Intent intent)
    {
        throw new NotImplementedException();
    }

    public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int starId)
    {
        if (intent.Action == "START_SERVICE")
        {
            System.Diagnostics.Debug.WriteLine("Se ha iniciado el servicio");
            // 仅当通知未注册时执行初始化逻辑
            if (!_notificationRegistered)
            {
                RegisterNotification();
                _notificationRegistered = true;
            }
        }
        else if (intent.Action == "STOP_SERVICE")
        {
            // 停止服务前先终止工作线程
            _stopThreadFlag = true;
            if (refrescar != null && refrescar.IsAlive)
            {
                refrescar.Join(1000);
            }
            _isThreadRunning = false;
            _notificationRegistered = false;
            StopForeground(true);
            StopSelfResult(starId);
        }
        return StartCommandResult.NotSticky;
    }

    private void RegisterNotification()
    {
        NotificationChannel channel = new NotificationChannel("ServicioChannel", "Demo de servicio", NotificationImportance.Max);
        NotificationManager manager = (NotificationManager)MainActivity.ActivityCurrent.GetSystemService(Context.NotificationService);
        manager.CreateNotificationChannel(channel);
        Notification notification = new Notification.Builder(this, "ServicioChannel").SetContentTitle("Servicio Trabajando").SetOngoing(true).Build();
        StartForeground(200, notification);

        IniciarServicio();
    }

    public void Start()
    {
        Intent startService = new Intent(MainActivity.ActivityCurrent, typeof(Servicio));
        startService.SetAction("START_SERVICE");
        MainActivity.ActivityCurrent.StartService(startService);
    }
    public void Stop()
    {
        Intent stopService = new Intent(MainActivity.ActivityCurrent, typeof(Servicio));
        stopService.SetAction("STOP_SERVICE");
        MainActivity.ActivityCurrent.StartService(stopService);
    }

    public int IniciarServicio()
    {
        // 线程已运行则直接返回,不重复创建
        if (_isThreadRunning && refrescar != null && refrescar.IsAlive)
        {
            return 0;
        }
        _stopThreadFlag = false;
        refrescar = new Thread(EsperaAlarma);
        refrescar.Start();
        _isThreadRunning = true;
        return 1;
    }

    // 去掉无用的async标记,原方法没有await逻辑
    public void EsperaAlarma()
    {
        WebClient cliente = new WebClient();
        byte[] respuesta;
        string resultado;
        while (!_stopThreadFlag)
        {
            respuesta = cliente.DownloadData(link);
            resultado = System.Text.Encoding.ASCII.GetString(respuesta);
            if (resultado == "Alerta")
            {
                setNotificationVolumeToMax();
                Device.BeginInvokeOnMainThread(() =>
                {
                    App.Current.MainPage = new Alerta();

                    var powerManager = (PowerManager)GetSystemService(PowerService);
                    var wakeLock = powerManager.NewWakeLock(WakeLockFlags.ScreenDim | WakeLockFlags.AcquireCausesWakeup, "Ejemplo");
                    wakeLock.Acquire();
                    Intent x = new Intent(MainActivity.ActivityCurrent.Intent);
                    StartActivity(x);
                });
                // 触发警报后终止线程
                _stopThreadFlag = true;
                break;
            }
            Thread.Sleep(3000);
        }
        cliente.Dispose();
        _isThreadRunning = false;
    }

    private void setNotificationVolumeToMax()
    {
        try
        {
            var audioManager = (AudioManager)GetSystemService(Context.AudioService);
            int max_volume = audioManager.GetStreamMaxVolume(Android.Media.Stream.Music);
            audioManager.SetStreamVolume(Android.Media.Stream.Music, max_volume, 0);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}

额外优化说明

  • 原方法EsperaAlarmaAsync标注了async但没有任何await逻辑,属于无效声明,已经移除避免异步异常被吞
  • 用控制变量_stopThreadFlag替代Thread.Abort(),后者属于不安全的线程终止方法,容易引发资源泄漏
  • 新增重复逻辑判断,避免每次重启应用都重复创建通知通道、注册前台服务、创建工作线程

内容的提问来源于stack exchange,提问作者Alí Emmanuel Flores Navarro

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 23:48:00