mcpField
M
maui-app-lifecycle

maui-app-lifecycle

github.com/davidortinau開発17656 回インストール17 週間前に更新
リポジトリ

maui-app-lifecycle について

.NET MAUI のライフサイクルイベントと状態を扱う開発者向けのスキルです。イベントの違い、ウィンドウごとの動作、保存と復元の時機、ハンドラーの性能制約を説明します。

主な機能

  1. 01アクティブ化・再開・停止イベントの区別
  2. 02Android の戻るボタンによる破棄への対応
  3. 03ウィンドウ単位のライフサイクル管理
  4. 04ハンドラーのブロック回避
  5. 05状態の保存と復元の計画
  6. 06iOS シーンライフサイクルの把握

活用シーン

  1. 01初回起動時に実行されない初期化処理の修正
  2. 02アプリ状態を保存するタイミングの選定
  3. 03マルチウィンドウアプリでの状態管理
  4. 04処理の遅いハンドラーによる終了リスクの低減

インストール

コマンドをコピーしてターミナルで実行します。

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

インストール後、Claude Code で/maui-app-lifecycleを入力して読み込まれたか確認します。

同梱ファイルreferences/lifecycle-api.md

詳細

.NET MAUI アプリのライフサイクル

注意が必要な動作

⚠️ Resumed ≠ 初回起動

Resumed は Stopped 状態から戻ったときにのみ発生します。初回起動時のシーケンスは Created → Activated であり、Resumed は呼び出されません。

// ❌ Putting initialization logic in OnResumed — won't run on first launch
protected override void OnResumed()
{
    LoadUserProfile();  // Skipped on cold start!
}

// ✅ Use OnActivated for logic that must run on every foreground entry
protected override void OnActivated()
{
    LoadUserProfile();  // Runs on both first launch and resume
}
⚠️ Deactivated ≠ Stopped

ダイアログ、画面分割、通知パネルのプルダウンでは、Stopped が発生せずに Deactivated が発生します。アプリが実際にバックグラウンドへ移行するとは限らないため、Deactivated で大きな状態を保存しないでください。

// ❌ Heavy save on every deactivation — fires too often
protected override void OnDeactivated()
{
    await SaveAllDataToDatabase();  // Wasteful for a dialog appearance
}

// ✅ Save state only when truly backgrounded
protected override void OnStopped()
{
    await SaveAllDataToDatabase();
}
⚠️ Android の戻るボタンでは Stopped が発生しない

Android では、アクティビティが終了すると、ハードウェアの戻るボタンを押したときに Stopped を経ずに Destroying が呼び出されることがあります。OnStopped のみで重要な保存処理を行うと、実行されない場合があります。

// ✅ Save in both Stopped and Destroying for safety on Android
protected override void OnStopped()
{
    base.OnStopped();
    SaveDraft();
}

protected override void OnDestroying()
{
    base.OnDestroying();
    SaveDraft();  // Catches Android back-button finish
}
⚠️ 複数ウィンドウでは個別に発生する

iPad、Mac Catalyst、デスクトップ版 Windows では、各 Window インスタンスのライフサイクルイベントが個別に発生します。ライフサイクルがグローバルに1つだけだと思い込まないでください。

パフォーマンス:ハンドラーを高速に保つ

ライフサイクルハンドラーで時間のかかる処理を行うと、Android では ANR による終了(タイムアウトは5秒)、iOS では ウォッチドッグによる終了(バックグラウンドでの実行時間に制限あり) の原因になります。

// ❌ Blocking the lifecycle handler
protected override void OnStopped()
{
    Thread.Sleep(3000);  // ANR on Android!
    SaveData();
}

// ✅ Fire-and-forget or use a brief async save
protected override void OnStopped()
{
    base.OnStopped();
    Preferences.Set("draft_text", _viewModel.DraftText);  // Fast, synchronous
}

大きな状態を保存する場合は、SecureStorage またはファイルベースのシリアル化を使用してください。ただし、処理は1~2秒以内に完了させてください。

iOS のシーンライフサイクル

iOS 13 以降では、シーンライフサイクル(SceneWillConnect など)が使用されます。古いデリゲートメソッドも MAUI 経由で引き続き呼び出されますが、最新の iOS ではシーンベースの API を対象にしてください。

状態保持のチェックリスト

  • 一時的な UI 状態(スクロール位置、下書きテキスト)を OnStopped で保存する
  • OnActivated ではなく OnResumed で状態を復元する(二重復元を避ける)
  • OnDeactivated では重い I/O を行わない(発生頻度が高すぎます)
  • Android:戻るボタンの場合に備え、重要な保存処理を OnDestroying でも行う
  • ライフサイクルハンドラーを2秒以内に完了させる
  • マルチウィンドウアプリでは、ウィンドウごとに個別に状態を処理する

コメント