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

Xamarin.Forms中OnSleep事件内SignalR方法无法稳定触发求助

问题根源与解决方案

核心问题在于Xamarin.Forms的OnSleep是同步生命周期方法,你在其中使用await执行异步操作时,系统不会等待异步任务完成就会挂起应用,导致代码偶尔无法执行完毕。以下是可行的解决思路:


1. 强制同步执行异步操作

将异步方法改为同步调用,确保操作在应用挂起前完成。可以通过GetAwaiter().GetResult()实现(注意:此方式需确保异步方法不会引发死锁,在OnSleep场景下风险较低):

protected override void OnSleep()
{
    online = false;
    
    // 提前读取Preferences,减少重复IO操作
    var userId = Preferences.Get("userid", "");
    var permission = Preferences.Get("permission", "");
    
    if (!string.IsNullOrEmpty(userId) && !string.IsNullOrEmpty(permission) && permission == "Student")
    {
        try
        {
            // 同步执行,确保操作完成
            SendMessage(userId, false).GetAwaiter().GetResult();
        }
        catch (Exception exp)
        {
            MessagingCenter.Send(this, App.UpdateStatusErrorMessage, exp.Message);
        }

        updateuserstatus(userId).GetAwaiter().GetResult();
    }
    
    base.OnSleep();
}

2. 利用平台特定后台任务机制

部分平台(如iOS)对OnSleep的执行时间有严格限制,需借助平台API申请额外后台执行时间:

iOS 端处理

通过BeginBackgroundTask申请后台时间,确保异步操作完成:

  1. 定义依赖服务接口:
public interface IBackgroundTaskService
{
    nint BeginBackgroundTask(string taskName);
    void EndBackgroundTask(nint taskId);
}
  1. iOS项目实现该接口:
[assembly: Dependency(typeof(BackgroundTaskService))]
namespace YourApp.iOS
{
    public class BackgroundTaskService : IBackgroundTaskService
    {
        public nint BeginBackgroundTask(string taskName)
        {
            return UIApplication.SharedApplication.BeginBackgroundTask(taskName, () => {});
        }

        public void EndBackgroundTask(nint taskId)
        {
            UIApplication.SharedApplication.EndBackgroundTask(taskId);
        }
    }
}
  1. 在OnSleep中使用:
protected override void OnSleep()
{
    online = false;
    
    var userId = Preferences.Get("userid", "");
    var permission = Preferences.Get("permission", "");
    nint backgroundTaskId = 0;
    
    if (!string.IsNullOrEmpty(userId) && !string.IsNullOrEmpty(permission) && permission == "Student")
    {
        var backgroundService = DependencyService.Get<IBackgroundTaskService>();
        backgroundTaskId = backgroundService.BeginBackgroundTask("UpdateUserStatus");
        
        try
        {
            SendMessage(userId, false).GetAwaiter().GetResult();
        }
        catch (Exception exp)
        {
            MessagingCenter.Send(this, App.UpdateStatusErrorMessage, exp.Message);
        }

        updateuserstatus(userId).GetAwaiter().GetResult();
        
        backgroundService.EndBackgroundTask(backgroundTaskId);
    }
    
    base.OnSleep();
}

Android 端处理

使用WorkManager调度一次性后台任务,确保状态更新操作被执行:

  1. 创建Worker类:
namespace YourApp.Droid
{
    public class UpdateStatusWorker : Worker
    {
        public UpdateStatusWorker(Context context, WorkerParameters workerParams) : base(context, workerParams)
        {
        }

        public override Result DoWork()
        {
            var userId = Preferences.Get("userid", "");
            try
            {
                SendMessage(userId, false).GetAwaiter().GetResult();
                updateuserstatus(userId).GetAwaiter().GetResult();
                return Result.Success();
            }
            catch (Exception)
            {
                return Result.Retry();
            }
        }
    }
}
  1. 在OnSleep中调度任务:
protected override void OnSleep()
{
    online = false;
    
    var userId = Preferences.Get("userid", "");
    var permission = Preferences.Get("permission", "");
    
    if (!string.IsNullOrEmpty(userId) && !string.IsNullOrEmpty(permission) && permission == "Student")
    {
#if ANDROID
        var workRequest = OneTimeWorkRequestBuilder<UpdateStatusWorker>().Build();
        WorkManager.Instance.Enqueue(workRequest);
#endif
        
        // 同步发送作为补充
        try
        {
            SendMessage(userId, false).GetAwaiter().GetResult();
        }
        catch (Exception exp)
        {
            MessagingCenter.Send(this, App.UpdateStatusErrorMessage, exp.Message);
        }
    }
    
    base.OnSleep();
}

额外注意事项

  • iOS后台任务时间限制约30秒,需确保操作尽可能简洁高效;
  • SignalR在后台可能断开连接,发送状态前需检查连接状态,必要时同步重新连接;
  • 务必在真实设备上测试,模拟器的后台行为与真实设备存在差异。

内容的提问来源于stack exchange,提问作者rana hd

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 04:22:08