Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
managedcode avatar

Maui App Lifecycle

  • 20 installs
  • 466 repo stars
  • Updated July 25, 2026
  • managedcode/dotnet-skills

Helps with ai & agent building tasks.

About

maui-app-lifecycle is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.

  • maui-app-lifecycle
  • AI & Agent Building
  • AI-coding skill

Maui App Lifecycle by the numbers

  • 20 all-time installs (skills.sh)
  • +1 installs in the week ending Aug 2, 2026 (Skillselion tracking)
  • Ranked #10,459 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
  • Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/managedcode/dotnet-skills --skill maui-app-lifecycle

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs20
repo stars466
Last updatedJuly 25, 2026
Repositorymanagedcode/dotnet-skills

What it does

Helps with ai & agent building tasks.

Files

SKILL.mdMarkdownGitHub ↗

.NET MAUI App Lifecycle

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.

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

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

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)

App States

A .NET MAUI app moves through four states:

StateDescription
Not RunningProcess does not exist
RunningForeground, receiving input
DeactivatedVisible but lost focus (dialog, split-screen, notification shade)
StoppedFully backgrounded, UI not visible

Typical flow: Not Running → Running → Deactivated → Stopped → Running (resumed) or Not Running (terminated).

Window Lifecycle Events

Microsoft.Maui.Controls.Window exposes six cross-platform events:

EventFires when
CreatedNative window allocated
ActivatedWindow receives input focus
DeactivatedWindow loses focus (may still be visible)
StoppedWindow is no longer visible
ResumedWindow returns to foreground after Stopped
DestroyingNative window is being torn down

Subscribing via CreateWindow

Override CreateWindow in your App class and attach event handlers:

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

Create a Window subclass and override the virtual methods:

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 CreateWindow:

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

Workflow: Save and Restore State on Background

1. Identify transient state — draft text, scroll position, form inputs, timer values. 2. Save in `OnStopped` — use Preferences for small values or file serialization for larger state. 3. Restore in `OnResumed` — read back saved values and apply to your view model. 4. Also save in `OnDestroying` on Android — the back button can skip Stopped entirely. 5. Keep handlers fast — complete within 1–2 seconds to avoid ANR on Android or watchdog kills on 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);
}

Platform Lifecycle Mapping

Android

Window EventAndroid Callback
CreatedOnCreate
ActivatedOnResume
DeactivatedOnPause
StoppedOnStop
ResumedOnRestartOnStartOnResume
DestroyingOnDestroy

iOS / Mac Catalyst

Window EventUIKit Callback
CreatedWillFinishLaunching / SceneWillConnect
ActivatedDidBecomeActive
DeactivatedWillResignActive
StoppedDidEnterBackground
ResumedWillEnterForeground
DestroyingWillTerminate

Windows (WinUI)

Window EventWinUI Callback
CreatedOnLaunched
ActivatedActivated (foreground)
DeactivatedActivated (background)
StoppedVisibilityChanged (false)
ResumedVisibilityChanged (true)
DestroyingClosed

Hooking Native Lifecycle Directly

Use ConfigureLifecycleEvents in MauiProgram.cs when you need platform-specific callbacks beyond what Window events provide:

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

1. Resumed does not fire on first launch. The initial sequence is CreatedActivated. Use OnActivated for logic that must run on every foreground entry, not OnResumed.

2. Deactivated ≠ Stopped. A dialog, split-screen, or notification pull-down triggers Deactivated without Stopped. Do not perform heavy saves in OnDeactivated — the app may never actually background.

3. Android back button skips Stopped. On Android, pressing back may call Destroying directly without Stopped. Place critical save logic in both OnStopped and OnDestroying.

4. Multi-window apps fire events independently. On iPad, Mac Catalyst, and desktop Windows each Window instance fires its own lifecycle events. Do not assume a single global lifecycle.

5. Long-running handlers cause kills. Android enforces a ~5 second ANR timeout; iOS has limited background execution time. Keep lifecycle handlers synchronous and fast — use Preferences for quick saves, not database writes.

6. Do not use legacy Xamarin.Forms lifecycle methods. Application.OnStart(), Application.OnSleep(), and Application.OnResume() exist for backward compatibility but bypass Window-level events. In .NET MAUI, prefer Window lifecycle events (OnActivated, OnStopped, OnResumed, etc.) for correct multi-window behavior.

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.