maui-app-lifecycle
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinese.NET MAUI App Lifecycle
.NET MAUI 应用生命周期
Handle application state transitions correctly in .NET MAUI. This skill covers the cross-platform Window lifecycle events, their platform-native mappings, and patterns for preserving state across backgrounding and resume cycles.
在.NET MAUI中正确处理应用状态转换。本技能涵盖跨平台Window生命周期事件、它们与原生平台的映射关系,以及在后台运行与恢复周期中保存状态的模式。
When to Use
适用场景
- Saving or restoring state when the app backgrounds or resumes
- Subscribing to Window lifecycle events (Created, Activated, Deactivated, Stopped, Resumed, Destroying)
- Hooking into platform-native lifecycle callbacks via
ConfigureLifecycleEvents - Deciding where to place initialization, teardown, or refresh logic
- Understanding the difference between Deactivated and Stopped
- 应用进入后台或恢复时保存/恢复状态
- 订阅Window生命周期事件(Created、Activated、Deactivated、Stopped、Resumed、Destroying)
- 通过挂钩原生平台生命周期回调
ConfigureLifecycleEvents - 确定初始化、销毁或刷新逻辑的放置位置
- 理解Deactivated与Stopped的区别
When Not to Use
不适用场景
- Page-level navigation events — use Shell navigation guidance instead
- Registering services at startup — use dependency injection guidance instead
- Calling platform-specific APIs outside lifecycle context — use platform invoke guidance instead
- 页面级导航事件——请改用Shell导航指南
- 启动时注册服务——请改用依赖注入指南
- 在生命周期上下文外调用平台特定API——请改用平台调用指南
Inputs
输入信息
- The target lifecycle transition (e.g., "save draft when backgrounded", "refresh data on resume")
- Which platforms the developer targets (Android, iOS, Mac Catalyst, Windows)
- Whether the app uses multiple windows (iPad, Mac Catalyst, desktop Windows)
- 目标生命周期转换(例如:“后台时保存草稿”、“恢复时刷新数据”)
- 开发者目标平台(Android、iOS、Mac Catalyst、Windows)
- 应用是否使用多窗口(iPad、Mac Catalyst、桌面端Windows)
App States
应用状态
A .NET MAUI app moves through four states:
| State | Description |
|---|---|
| Not Running | Process does not exist |
| Running | Foreground, receiving input |
| Deactivated | Visible but lost focus (dialog, split-screen, notification shade) |
| Stopped | Fully backgrounded, UI not visible |
Typical flow: Not Running → Running → Deactivated → Stopped → Running (resumed) or Not Running (terminated).
.NET MAUI应用会经历四种状态:
| 状态 | 描述 |
|---|---|
| 未运行 | 进程不存在 |
| 运行中 | 处于前台,接收输入 |
| 已失活 | 可见但失去焦点(弹窗、分屏、通知栏) |
| 已停止 | 完全进入后台,UI不可见 |
典型流程:未运行 → 运行中 → 已失活 → 已停止 → 运行中(恢复)或未运行(终止)。
Window Lifecycle Events
Window生命周期事件
Microsoft.Maui.Controls.Window| Event | Fires when |
|---|---|
| Native window allocated |
| Window receives input focus |
| Window loses focus (may still be visible) |
| Window is no longer visible |
| Window returns to foreground after Stopped |
| Native window is being torn down |
Microsoft.Maui.Controls.Window| 事件 | 触发时机 |
|---|---|
| 原生窗口已分配 |
| 窗口获得输入焦点 |
| 窗口失去焦点(可能仍可见) |
| 窗口不再可见 |
| 窗口从Stopped状态返回前台 |
| 原生窗口正在被销毁 |
Subscribing via CreateWindow
通过CreateWindow订阅
Override in your class and attach event handlers:
CreateWindowAppcsharp
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;
}
}在类中重写并附加事件处理程序:
AppCreateWindowcsharp
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;
}
}Subscribing via a Custom Window Subclass
通过自定义Window子类订阅
Create a subclass and override the virtual methods:
Windowcsharp
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 */ }
}Return it from :
CreateWindowcsharp
protected override Window CreateWindow(IActivationState? activationState)
=> new AppWindow(new AppShell());创建子类并重写虚拟方法:
Windowcsharp
public class AppWindow : Window
{
public AppWindow(Page page) : base(page) { }
protected override void OnActivated() { /* 刷新UI */ }
protected override void OnStopped() { /* 保存状态 */ }
protected override void OnResumed() { /* 恢复状态 */ }
protected override void OnDestroying() { /* 清理资源 */ }
}从返回该子类:
CreateWindowcsharp
protected override Window CreateWindow(IActivationState? activationState)
=> new AppWindow(new AppShell());Workflow: Save and Restore State on Background
工作流:后台时保存与恢复状态
- Identify transient state — draft text, scroll position, form inputs, timer values.
- Save in — use
OnStoppedfor small values or file serialization for larger state.Preferences - Restore in — read back saved values and apply to your view model.
OnResumed - Also save in on Android — the back button can skip
OnDestroyingentirely.Stopped - Keep handlers fast — complete within 1–2 seconds to avoid ANR on Android or watchdog kills on iOS.
csharp
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);
}- 识别临时状态——草稿文本、滚动位置、表单输入、计时器值。
- 在中保存——小型值使用
OnStopped,大型状态使用文件序列化。Preferences - 在中恢复——读取保存的值并应用到视图模型。
OnResumed - 在Android的中也保存——返回按钮可能会直接跳过
OnDestroying。Stopped - 保持处理程序快速——在1-2秒内完成,避免Android出现ANR或iOS被看门狗杀死。
csharp
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返回按钮可能会跳过Stopped
Preferences.Set("draft_text", _viewModel.DraftText);
}Platform Lifecycle Mapping
平台生命周期映射
Android
Android
| Window Event | Android Callback |
|---|---|
| Created | |
| Activated | |
| Deactivated | |
| Stopped | |
| Resumed | |
| Destroying | |
| Window事件 | Android回调 |
|---|---|
| Created | |
| Activated | |
| Deactivated | |
| Stopped | |
| Resumed | |
| Destroying | |
iOS / Mac Catalyst
iOS / Mac Catalyst
| Window Event | UIKit Callback |
|---|---|
| Created | |
| Activated | |
| Deactivated | |
| Stopped | |
| Resumed | |
| Destroying | |
| Window事件 | UIKit回调 |
|---|---|
| Created | |
| Activated | |
| Deactivated | |
| Stopped | |
| Resumed | |
| Destroying | |
Windows (WinUI)
Windows (WinUI)
| Window Event | WinUI Callback |
|---|---|
| Created | |
| Activated | |
| Deactivated | |
| Stopped | |
| Resumed | |
| Destroying | |
| Window事件 | WinUI回调 |
|---|---|
| Created | |
| Activated | |
| Deactivated | |
| Stopped | |
| Resumed | |
| Destroying | |
Hooking Native Lifecycle Directly
直接挂钩原生生命周期
Use in when you need platform-specific callbacks beyond what Window events provide:
ConfigureLifecycleEventsMauiProgram.cscsharp
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
.DidBecomeActive(app => Debug.WriteLine("iOS DidBecomeActive"))
.WillResignActive(app => Debug.WriteLine("iOS WillResignActive"))
.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
});当需要Window事件之外的平台特定回调时,在中使用:
MauiProgram.csConfigureLifecycleEventscsharp
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
.DidBecomeActive(app => Debug.WriteLine("iOS DidBecomeActive"))
.WillResignActive(app => Debug.WriteLine("iOS WillResignActive"))
.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
});Common Pitfalls
常见陷阱
-
Resumed does not fire on first launch. The initial sequence is→
Created. UseActivatedfor logic that must run on every foreground entry, notOnActivated.OnResumed -
Deactivated ≠ Stopped. A dialog, split-screen, or notification pull-down triggerswithout
Deactivated. Do not perform heavy saves inStopped— the app may never actually background.OnDeactivated -
Android back button skips Stopped. On Android, pressing back may calldirectly without
Destroying. Place critical save logic in bothStoppedandOnStopped.OnDestroying -
Multi-window apps fire events independently. On iPad, Mac Catalyst, and desktop Windows eachinstance fires its own lifecycle events. Do not assume a single global lifecycle.
Window -
Long-running handlers cause kills. Android enforces a ~5 second ANR timeout; iOS has limited background execution time. Keep lifecycle handlers synchronous and fast — usefor quick saves, not database writes.
Preferences -
Do not use legacy Xamarin.Forms lifecycle methods.,
Application.OnStart(), andApplication.OnSleep()exist for backward compatibility but bypass Window-level events. In .NET MAUI, preferApplication.OnResume()lifecycle events (Window,OnActivated,OnStopped, etc.) for correct multi-window behavior.OnResumed
-
首次启动时不会触发Resumed。初始序列是→
Created。对于必须在每次进入前台时运行的逻辑,请使用Activated而非OnActivated。OnResumed -
Deactivated ≠ Stopped。弹窗、分屏或下拉通知会触发但不会触发
Deactivated。不要在Stopped中执行大量保存操作——应用可能并未真正进入后台。OnDeactivated -
Android返回按钮会跳过Stopped。在Android上,按下返回按钮可能直接调用而不经过
Destroying。请将关键保存逻辑同时放在Stopped和OnStopped中。OnDestroying -
多窗口应用会独立触发事件。在iPad、Mac Catalyst和桌面端Windows上,每个实例都会触发自己的生命周期事件。不要假设存在单一全局生命周期。
Window -
长时间运行的处理程序会导致应用被杀死。Android强制执行约5秒的ANR超时;iOS的后台执行时间有限。保持生命周期处理程序同步且快速——使用进行快速保存,而非数据库写入。
Preferences -
不要使用旧版Xamarin.Forms生命周期方法。、
Application.OnStart()和Application.OnSleep()仅为向后兼容而存在,但会绕过Window级事件。在.NET MAUI中,为了实现正确的多窗口行为,优先使用Application.OnResume()生命周期事件(Window、OnActivated、OnStopped等)。OnResumed