mcpField
M
maui-app-lifecycle

maui-app-lifecycle

github.com/dotnet开发5.8k3.4k 次安装1 天前更新
代码仓库

关于 maui-app-lifecycle

.NET MAUI App Lifecycle 是面向 .NET MAUI 开发者的技能,说明应用窗口状态变化及跨平台生命周期事件。它涵盖原生回调映射和应用进入后台、恢复时的状态保存方法。

主要功能

  1. 01说明六种窗口生命周期事件
  2. 02对照 Android、iOS、Mac Catalyst 和 Windows 回调
  3. 03讲解后台保存与恢复状态
  4. 04演示订阅窗口事件和重写方法
  5. 05说明 ConfigureLifecycleEvents 的用法
  6. 06指出多窗口及生命周期常见陷阱

适用场景

  1. 01应用切到后台时保存草稿或表单
  2. 02应用恢复前台时刷新界面或还原状态
  3. 03需要接入平台原生生命周期回调
  4. 04区分窗口失焦与应用进入后台

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dotnet/skills --skill maui-app-lifecycle

安装后在 Claude Code 中输入/maui-app-lifecycle确认已加载。

附带文件references/lifecycle-api.md

详细介绍

.NET MAUI 应用生命周期

在 .NET MAUI 中正确处理应用状态转换。本技能介绍跨平台的 Window 生命周期事件、它们与平台原生事件的映射关系,以及在应用进入后台和恢复时保留状态的模式。

适用场景

  • 应用进入后台或恢复时保存或还原状态
  • 订阅 Window 生命周期事件(Created、Activated、Deactivated、Stopped、Resumed、Destroying)
  • 通过 ConfigureLifecycleEvents 挂接平台原生生命周期回调
  • 决定将初始化、清理或刷新逻辑放在哪里
  • 了解 Deactivated 和 Stopped 之间的区别

不适用场景

  • 页面级导航事件——请改用 Shell 导航指南
  • 在启动时注册服务——请改用依赖注入指南
  • 在生命周期上下文之外调用特定于平台的 API——请改用平台调用指南

输入

  • 目标生命周期转换(例如“应用进入后台时保存草稿”“恢复时刷新数据”)
  • 开发者目标平台(Android、iOS、Mac Catalyst、Windows)
  • 应用是否使用多个窗口(iPad、Mac Catalyst、桌面版 Windows)

应用状态

.NET MAUI 应用会经历四种状态:

状态描述
未运行进程不存在
运行中位于前台,正在接收输入
已停用仍然可见,但已失去焦点(对话框、分屏、通知栏)
已停止完全进入后台,UI 不可见

典型流程:未运行 → 运行中 → 已停用 → 已停止 → 运行中(已恢复)或未运行(已终止)。

Window 生命周期事件

Microsoft.Maui.Controls.Window 提供六个跨平台事件:

事件触发时机
Created已分配原生窗口
Activated窗口获得输入焦点
Deactivated窗口失去焦点(可能仍然可见)
Stopped窗口不再可见
Resumed窗口在 Stopped 后返回前台
Destroying正在销毁原生窗口
通过 CreateWindow 订阅

在 App 类中重写 CreateWindow 并附加事件处理程序:

public partial class App : Application
{
    protected override Window CreateWindow(IActivationState? activationState)
    {
        var window = base.CreateWindow(activationState);

        window.Created += (s, e) => Debug.WriteLine("Created");
        window.Activated += (s, e) => Debug.WriteLine("Activated");
        window.Deactivated += (s, e) => Debug.WriteLine("Deactivated");
        window.Stopped += (s, e) => Debug.WriteLine("Stopped");
        window.Resumed += (s, e) => Debug.WriteLine("Resumed");
        window.Destroying += (s, e) => Debug.WriteLine("Destroying");

        return window;
    }
}
通过自定义 Window 子类订阅

创建 Window 子类并重写虚方法:

public class AppWindow : Window
{
    public AppWindow(Page page) : base(page) { }

    protected override void OnActivated() { /* refresh UI */ }
    protected override void OnStopped() { /* save state */ }
    protected override void OnResumed() { /* restore state */ }
    protected override void OnDestroying() { /* cleanup */ }
}

从 CreateWindow 返回该子类:

protected override Window CreateWindow(IActivationState? activationState)
    => new AppWindow(new AppShell());

工作流:在应用进入后台时保存和还原状态

  1. 识别临时状态——草稿文本、滚动位置、表单输入、计时器值。
  2. 在 OnStopped 中保存——小型值使用 Preferences,较大的状态使用文件序列化。
  3. 在 OnResumed 中还原——读取已保存的值并应用到视图模型。
  4. 在 Android 上也要在 OnDestroying 中保存——返回按钮可能会完全跳过 Stopped。
  5. 确保处理程序运行迅速——在 1–2 秒内完成,以避免 Android 上发生 ANR,或 iOS 上被看门狗终止。
protected override void OnStopped()
{
    base.OnStopped();
    Preferences.Set("draft_text", _viewModel.DraftText);
    Preferences.Set("scroll_y", _viewModel.ScrollY);
}

protected override void OnResumed()
{
    base.OnResumed();
    _viewModel.DraftText = Preferences.Get("draft_text", string.Empty);
    _viewModel.ScrollY = Preferences.Get("scroll_y", 0.0);
}

protected override void OnDestroying()
{
    base.OnDestroying();
    // Android back-button can skip Stopped
    Preferences.Set("draft_text", _viewModel.DraftText);
}

平台生命周期映射

Android
Window 事件Android 回调
CreatedOnCreate
ActivatedOnResume
DeactivatedOnPause
StoppedOnStop
ResumedOnRestart → OnStart → OnResume
DestroyingOnDestroy
iOS / Mac Catalyst
Window 事件UIKit 回调AddiOS 生成器方法
CreatedWillFinishLaunching / SceneWillConnect.WillFinishLaunching() / .SceneWillConnect()
ActivatedDidBecomeActive.OnActivated()
DeactivatedWillResignActive.OnResignActivation()
StoppedDidEnterBackground.DidEnterBackground()
ResumedWillEnterForeground.WillEnterForeground()
DestroyingWillTerminate.WillTerminate()

⚠️ UIKit 选择器名称与 AddiOS 生成器方法名称在激活事件上有所不同。不存在 .DidBecomeActive() 或 .WillResignActive() 生成器方法——请使用 .OnActivated() 和 .OnResignActivation(),否则代码将无法编译。

Windows(WinUI)
窗口事件WinUI 回调
创建OnLaunched
激活Activated(前台)
停用Activated(后台)
停止VisibilityChanged(false)
恢复VisibilityChanged(true)
销毁Closed

直接挂接原生生命周期

当你需要使用 Window 事件未提供的平台专属回调时,请在 MauiProgram.cs 中使用 ConfigureLifecycleEvents:

builder.ConfigureLifecycleEvents(events =>
{
#if ANDROID
    events.AddAndroid(android => android
        .OnCreate((activity, bundle) => Debug.WriteLine("Android OnCreate"))
        .OnResume(activity => Debug.WriteLine("Android OnResume"))
        .OnPause(activity => Debug.WriteLine("Android OnPause"))
        .OnStop(activity => Debug.WriteLine("Android OnStop"))
        .OnDestroy(activity => Debug.WriteLine("Android OnDestroy")));
#elif IOS || MACCATALYST
    events.AddiOS(ios => ios
        .OnActivated(app => Debug.WriteLine("iOS OnActivated"))
        .OnResignActivation(app => Debug.WriteLine("iOS OnResignActivation"))
        .DidEnterBackground(app => Debug.WriteLine("iOS DidEnterBackground"))
        .WillEnterForeground(app => Debug.WriteLine("iOS WillEnterForeground")));
#elif WINDOWS
    events.AddWindows(windows => windows
        .OnLaunched((app, args) => Debug.WriteLine("Windows OnLaunched"))
        .OnActivated((window, args) => Debug.WriteLine("Windows Activated"))
        .OnClosed((window, args) => Debug.WriteLine("Windows Closed")));
#endif
});

常见陷阱

  1. 首次启动时不会触发 Resumed。 初始事件序列为 Created → Activated。对于每次进入前台时都必须运行的逻辑,请使用 OnActivated,而不是 OnResumed。

  2. Deactivated 不等于 Stopped。 对话框、分屏或下拉通知会触发 Deactivated,但不会触发 Stopped。不要在 OnDeactivated 中执行耗时的保存操作——应用可能根本不会进入后台。

  3. Android 返回按钮会跳过 Stopped。 在 Android 上,按下返回按钮可能会直接调用 Destroying,而不触发 Stopped。请将关键保存逻辑放在 OnStopped 和 OnDestroying 中。

  4. 多窗口应用会独立触发事件。 在 iPad、Mac Catalyst 和桌面版 Windows 上,每个 Window 实例都会触发生命周期事件。不要假设只有一个全局生命周期。

  5. 长时间运行的处理程序可能导致应用被终止。 Android 强制执行约 5 秒的 ANR 超时;iOS 的后台执行时间有限。请确保生命周期处理程序同步且快速——快速保存请使用 Preferences,而不要写入数据库。

  6. 不要使用旧版 Xamarin.Forms 生命周期方法。 Application.OnStart()、Application.OnSleep() 和 Application.OnResume() 为向后兼容而保留,但会绕过 Window 级别的事件。在 .NET MAUI 中,请优先使用 Window 生命周期事件(OnActivated、OnStopped、OnResumed 等),以确保多窗口行为正确。

评论

支持 Markdown