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

Xamarin中MainActivity被销毁后如何创建通知并解决异常?

问题分析与解决方案

问题概述

应用基于周期性后台任务,活跃状态运行正常,但数小时后系统会杀死MainActivity(已获取电池不优化权限),后台服务仍持续运行。此时后台服务显示通知时抛出异常:You must call Xamarin.Forms.Forms.Init(); prior to using this property.,且无法启动依赖通知的前台服务。尝试通过广播显示通知时,manager.Notify(messageId++, notification);处出现NullReference异常。

核心问题定位

  • Xamarin.Forms初始化异常:后台服务调用通知时,因MainActivity被销毁,Xamarin.Forms上下文未初始化,导致依赖Forms的代码报错。
  • NullReference异常(广播方案):BroadcastReceiver中的manager变量未初始化,直接调用Notify触发空引用。

具体修复步骤

1. 修复广播接收器的空引用问题

在BroadcastReceiver的OnReceive方法中,先初始化NotificationManager:

public override void OnReceive(Context context, Intent intent)
{
    // 初始化NotificationManager
    manager = (NotificationManager)context.GetSystemService(Context.NotificationService);
    
    PendingIntent pendingIntent = PendingIntent.GetActivity(AndroidApp.Context, pendingIntentId, intent, PendingIntentFlags.OneShot | PendingIntentFlags.Immutable);

    string title = intent.GetStringExtra(AndroidNotificationManager.TitleKey);
    string message = intent.GetStringExtra(AndroidNotificationManager.MessageKey);

    NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId)
            .SetContentIntent(pendingIntent)
            .SetContentTitle(title)
            .SetContentText(message)
            .SetLargeIcon(BitmapFactory.DecodeResource(context.Resources, Resource.Drawable.Logo2_6_10x10))
            .SetSmallIcon(Resource.Drawable.Logo2_6_10x10)
            .SetStyle(new NotificationCompat.BigTextStyle().BigText(message));
    Notification notification = builder.Build();

    notification.Flags = NotificationFlags.AutoCancel;

    manager.Notify(messageId++, notification);
}

2. 脱离Xamarin.Forms上下文显示通知

后台服务中直接使用Android原生API创建通知,依赖Application上下文而非MainActivity,避免Forms初始化限制:

public void Show(string title, string message, int Id, string Type)
{
    try
    {
        var appContext = global::Android.App.Application.Context;
        // Android 8.0+必须先创建通知渠道
        CreateNotificationChannel(appContext);

        Intent intent = new Intent(appContext, typeof(MainActivity));
        intent.AddFlags(ActivityFlags.SingleTop);
        intent.PutExtra(TitleKey, title);
        intent.PutExtra(MessageKey, message);
        intent.PutExtra(MsgIdKey, Id.ToString());
        intent.PutExtra(MsgTypeKey, Type);
        
        var pendingFlags = PendingIntentFlags.UpdateCurrent;
        if ((int)Build.VERSION.SdkInt >= 33)
            pendingFlags |= PendingIntentFlags.Immutable;
        PendingIntent pendingIntent = PendingIntent.GetActivity(appContext, pendingIntentId++, intent, pendingFlags);

        NotificationCompat.Builder builder = new NotificationCompat.Builder(appContext, channelId)
            .SetContentIntent(pendingIntent)
            .SetContentTitle(title)
            .SetContentText(message)
            .SetLargeIcon(BitmapFactory.DecodeResource(appContext.Resources, Resource.Drawable.Logo2_6_10x10))
            .SetSmallIcon(Resource.Drawable.Logo2_6_10x10)
            .SetStyle(new NotificationCompat.BigTextStyle().BigText(message));
        Notification notification = builder.Build();

        notification.Flags = NotificationFlags.AutoCancel;

        var notificationManager = (NotificationManager)appContext.GetSystemService(Context.NotificationService);
        notificationManager.Notify(messageId++, notification);
    }
    catch(Exception ex)
    {
        Console.WriteLine($"通知显示失败:{ex.Message}");
    }
}

// 创建通知渠道的辅助方法
private void CreateNotificationChannel(Context context)
{
    if ((int)Build.VERSION.SdkInt >= 26)
    {
        var channel = new NotificationChannel(channelId, "默认通知渠道", NotificationImportance.Default)
        {
            Description = "应用通知渠道"
        };
        var notificationManager = (NotificationManager)context.GetSystemService(Context.NotificationService);
        notificationManager.CreateNotificationChannel(channel);
    }
}

3. 优化后台服务存活能力

将后台服务设为前台服务,启动时立即显示前台通知,降低被系统杀死的概率:

public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
    // 创建前台通知
    var foregroundNotification = new NotificationCompat.Builder(this, channelId)
        .SetContentTitle("后台服务运行中")
        .SetContentText("应用正在后台执行周期性任务")
        .SetSmallIcon(Resource.Drawable.Logo2_6_10x10)
        .Build();

    // 启动前台服务
    StartForeground(1, foregroundNotification);
    
    // 执行周期性任务逻辑
    return StartCommandResult.Sticky;
}

注意:Android 12+需在AndroidManifest.xml中添加<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />权限。

4. 简化方案(可选)

如果直接通过后台服务原生API显示通知能解决问题,可移除广播中转逻辑,减少代码复杂度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 08:07:04