一般にアプリケーションと呼ばれるものにはライフサイクルというものが存在します。ライフサイクルとはプログラムの処理順序であり、アプリケーションの開発者はプラットフォームのライフサイクルを理解し、適切な状態で適切な処理を記述しないと予期せぬ動作を引き起こすことになります。
この予期せぬ動作は、時にはアプリケーション開発者を助けてくれますがたいていの場合はバグとなり開発者を苦しめることでしょう。
今回はアプリケーション開発者に常に付きまとうライフサイクルについて解説します。
詳細は以下から。
まずはライフサイクルにどのようなものがあるのか見てみましょう。
下図はWindows Phone7(以降WP7)におけるライフサイクルを簡易的に表現したものです。
ライフサイクルの起点はLaunchingイベントであり、終点はClosingイベントとなります。
図中の赤はApplicationクラスのイベント、青はPhoneApplicationPageクラスのメソッド、緑は状態となります。
赤の部分の処理はApplicationクラスを継承したクラスに記述します。
プロジェクトを作成した初期状態で自動的にApp.xaml.csというファイルが生成されているはずです。
これがApplicationクラスを継承したクラスのソースコードになります。
青の部分の処理はMainPage.xaml.csに記述します。
これまでtechboosterで紹介してきたサンプルでは”MainPage.xaml.cs”についてのみ言及しています。
青の部分のメソッドは初期生成段階では記述されていませんので、クラススコープ内でoverrideと半角スペースを入力し、ctrl+スペースを押下して該当するメソッドを選択すると自動生成してくれます。
では各項目について解説していきます。
Launching イベント
アプリケーションがユーザー操作によって起動された場合に発生するイベントです。
アプリケーションの新規インスタンスが作成されるため、このイベントが発生した後は、操作が継続されているような状態を表示するべきではありません。
ゲームを例にすると、このイベントが発生した後は、プレイの途中の状態を表示するのではなく、タイトル画面を表示するべきです。
また、初回起動に発生するからといって、ファイル読み込みやネットワークへの接続など負荷のかかる処理を記述するべきではありません。
実行中
アプリケーションが実行されている状態です。
“MainPage.xaml.cs”に記述されている処理(PhoneApplicationPageを継承したクラスの処理)はこの段階で実行されます。
OnNavigatedFrom メソッド
ページ移動を行うと呼ばれるメソッドです。
アプリケーションがフォアグラウンドでなくなった場合もこのメソッドが呼ばれます。
ここではユーザーが別のページから戻ってきた場合に、移動前と同じ表示内容を表示できるように値を保持する処理を記述します。
ただし、前のページに戻る処理の場合は値の保持を行う必要はありません。
前のページに戻る操作かどうかはNavigationModeプロパティを使用することで判定できます。
NavigationModeプロパティには以下の種類があります。
[table “184” not found /]Deactivated イベント
ユーザーが次のページに移動した場合、[スタート]キー(端末下部のWindowsロゴ)が押下された場合、他のアプリが起動された場合に発生します。
また、アプリケーションがアイドル検出を無効にしていなければ、デバイスがロック画面になった場合にも発生します。
アイドル検出については別の機会に解説しますので、ここではデバイスがロック画面になった場合にDeactivated イベントが発生することだけ覚えておいてください。
ここではアプリケーションの表示状態を保持しておく必要があります。
OnNavigatedFrom メソッドとの違いは値を保持するために便利なStateプロパティを使用することができる点です。
休止状態
Deactivated イベント発生後にこの状態になります。この状態ではバックグラウンドを含めた全てのスレッドは停止しますが、まだメモリの解放などは行われないため、この状態からアプリが復旧した場合は特別な処理を行わなくても表示状態は保持されています。
廃棄状態
休止状態に他のアプリが起動するために十分な空きメモリがない場合にこの状態になり、メモリの解放が行われます。
メモリの解放が行われても、Stateプロパティに保持した値は保持されているため、この状態からのアプリの復旧は可能です。
しかし長時間ユーザーが戻ってこない場合はアプリケーションが終了し、Stateプロパティの値も解放されます。
Activated イベント
ユーザーが休止状態や廃棄状態から戻ってきた場合に呼ばれます。IsApplicationInstancePreservedプロパティを参照することで、休止状態から戻ってきたのか、廃棄状態から戻ってきたのかを判断します。
IsApplicationInstancePreservedプロパティがtrueの場合は休止状態からの復旧であるため、特に処理を行う必要はありません。
falseの場合は廃棄状態からの復旧のため、Stateプロパティを使用して、表示状態を復元してください。
また表示内容を復元するためでも、ファイルの読み込みやネットワークへの接続などの高負荷な処理は実行するべきではありません。アプリケーションのスムーズな復旧を阻害し、ユーザーに不快感を与えます。
OnNavigatedTo メソッド
アプリケーションの初回起動、アプリ間のページ移動、アプリが休止/廃棄状態から復旧した場合に呼ばれます。
ここではアプリの復旧処理を行うべきですが、NavigationModeプロパティがNewの場合以外は復旧処理を行う必要はありません。
Closing イベント
アプリが完全に終了する場合に発生します。ここが終了前の最後のイベントですので、保存しておくべきデータを保存します。
しかし、このイベント内の処理は10秒間しか実行されないため、大量のファイルI/Oやネットワークを使用したデータの保存などは避けるべきです。
重要なデータの保存は都度データ取得時に実行しておくべきです。
下記は各イベントが発生した場合にMainPage.xaml上のTextblockに実行順で実行されたイベントやメソッドが表示されるサンプルです。
画面下部にあるボタンは押下すると次ページへ遷移するようになっているので、色々な操作を行ってみて実際にライフサイクルの流れを確認してみて下さい。
※下記サンプル中の”Page1.xaml.cs”は自動生成されないため、こちらを参考に画面を追加してください。
App.xaml.cs
public partial class App : Application { ~省略~ private void Application_Launching(object sender, LaunchingEventArgs e) { MainPage.testStr += "Application_Launching\r\n"; } private void Application_Activated(object sender, ActivatedEventArgs e) { MainPage.testStr += "Application_Activated\r\n"; } private void Application_Deactivated(object sender, DeactivatedEventArgs e) { MainPage.testStr += "Application_Deactivated\r\n"; } ~省略~ }
MainPage.xaml.cs
public partial class MainPage : PhoneApplicationPage { public static String testStr; // コンストラクター public MainPage() { InitializeComponent(); } protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e) { base.OnNavigatedFrom(e); if (e.NavigationMode == System.Windows.Navigation.NavigationMode.Forward) { testStr += "メインページ : OnNavigatedTo : Forward\r\n"; } else if (e.NavigationMode == System.Windows.Navigation.NavigationMode.Back) { testStr += "メインページ : OnNavigatedTo : Back\r\n"; } else if (e.NavigationMode == System.Windows.Navigation.NavigationMode.New) { testStr += "メインページ : OnNavigatedTo : New\r\n"; } else if (e.NavigationMode == System.Windows.Navigation.NavigationMode.Refresh) { testStr += "メインページ : OnNavigatedTo : Refresh\r\n"; } textBlock1.Text = testStr; } protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { base.OnNavigatedTo(e); if (e.NavigationMode == System.Windows.Navigation.NavigationMode.Forward) { testStr += "メインページ : OnNavigatedTo : Forward\r\n"; } else if (e.NavigationMode == System.Windows.Navigation.NavigationMode.Back) { testStr += "メインページ : OnNavigatedTo : Back\r\n"; } else if (e.NavigationMode == System.Windows.Navigation.NavigationMode.New) { testStr += "メインページ : OnNavigatedTo : New\r\n"; } else if (e.NavigationMode == System.Windows.Navigation.NavigationMode.Refresh) { testStr += "メインページ : OnNavigatedTo : Refresh\r\n"; } textBlock1.Text = testStr; } private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e) { textBlock1.Text = testStr; } private void button1_Click(object sender, RoutedEventArgs e) { NavigationService.Navigate(new Uri("/Page1.xaml", UriKind.Relative)); } }
Page1.xaml.cs
public partial class MainPage : PhoneApplicationPage { public static String testStr; // コンストラクター public MainPage() { InitializeComponent(); } protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e) { base.OnNavigatedFrom(e); if (e.NavigationMode == System.Windows.Navigation.NavigationMode.Forward) { MainPage.testStr += "ページ1 : OnNavigatedTo : Forward\r\n"; } else if (e.NavigationMode == System.Windows.Navigation.NavigationMode.Back) { MainPage.testStr += "ページ1 : OnNavigatedTo : Back\r\n"; } else if (e.NavigationMode == System.Windows.Navigation.NavigationMode.New) { MainPage.testStr += "ページ1 : OnNavigatedTo : New\r\n"; } else if (e.NavigationMode == System.Windows.Navigation.NavigationMode.Refresh) { MainPage.testStr += "ページ1 : OnNavigatedTo : Refresh\r\n"; } textBlock1.Text = testStr; } protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { base.OnNavigatedTo(e); if (e.NavigationMode == System.Windows.Navigation.NavigationMode.Forward) { MainPage.testStr += "ページ1 : OnNavigatedTo : Forward\r\n"; } else if (e.NavigationMode == System.Windows.Navigation.NavigationMode.Back) { MainPage.testStr += "ページ1 : OnNavigatedTo : Back\r\n"; } else if (e.NavigationMode == System.Windows.Navigation.NavigationMode.New) { MainPage.testStr += "ページ1 : OnNavigatedTo : New\r\n"; } else if (e.NavigationMode == System.Windows.Navigation.NavigationMode.Refresh) { MainPage.testStr += "ページ1 : OnNavigatedTo : Refresh\r\n"; } textBlock1.Text = testStr; } }
以上がWP7のライフサイクルの内容となります。
Stateプロパティでの値の保持方法などは別の機会に詳しく紹介します。