過去記事
Activityのライフサイクル
Activityのライフサイクルについて説明します。Activityのライフサイクルで呼び出されるメソッドは以下の7つがあります。があります。
- OnCreateメソッド: Activityが作成されたときに呼び出される。
- OnStartメソッド: アクティビティがユーザーに表示される直前に呼び出される。
- OnResumeメソッド: アクティビティがユーザーとの操作が開始される直前に呼び出される。
- OnPauseメソッド: 別のアクティビティを表示する直前に呼び出される
- OnStopメソッド: アクティビティがユーザーから見えなくなると表示される
- OnDestroyメソッド: アクティビティが破棄される前に呼び出される
- OnRestartメソッド: アクティビティが停止したあと再開する直前に呼び出される
通常は、OnCreateメソッドで初期化処理を行い、OnPauseメソッドで未保存の永続化データを保存すると良いでしょう。別のActivityが表示されると、もともと表示されていたActivityは、通常OnPause→OnStopが呼び出されて次の表示が来るまで待ちますが、メモリが圧迫されたりするとActivityが破棄されたりします。そうなると、次に戻ってきたときはOnCreateからやり直しになります。その時、EditTextなどの入力途中のデータなどは、IDが振られていると、自動的に復元されます。その他のユーザーがActivityのフィールドなどに保持していたデータは何もしないとクリアされてしまいます。これに対応するためには、OnSaveInstanceStateメソッドをオーバーライドして、Bundleにデータを保存します。OnCreateの引数で渡されるBundleがnullじゃないときは、保存されたデータがあるということなので、データの復元をBundleから行います。 この動作を確認するためのプログラムを以下に示します。MainActivityとNextActivityを持っただけのシンプルなプロジェクトで、以下のようなコードを記述します。
using Android.App; using Android.Content; using Android.OS; using Android.Util; using Android.Views; using Java.Interop; using System; namespace ActivityLifecycle { [Activity(Label = "ActivityLifecycle", MainLauncher = true, Icon = "@drawable/icon")] publicclass MainActivity : Activity { privatestring Id { get; set; } protectedoverridevoid OnSaveInstanceState(Bundle outState) { base.OnSaveInstanceState(outState); Log.Debug(nameof(MainActivity), $"{nameof(OnSaveInstanceState)}: {this.Id}"); outState.PutString(nameof(Id), this.Id); } protectedoverridevoid OnCreate(Bundle bundle) { base.OnCreate(bundle); // Set our view from the "main" layout resourcethis.SetContentView(Resource.Layout.Main); if (bundle == null) { this.Id = Guid.NewGuid().ToString(); } else { this.Id = bundle.GetString(nameof(Id)); } Log.Debug(nameof(MainActivity), $"{nameof(OnCreate)}: {this.Id}"); } protectedoverridevoid OnStart() { base.OnStart(); Log.Debug(nameof(MainActivity), $"{nameof(OnStart)}: {this.Id}"); } protectedoverridevoid OnResume() { base.OnResume(); Log.Debug(nameof(MainActivity), $"{nameof(OnResume)}: {this.Id}"); } protectedoverridevoid OnRestart() { base.OnRestart(); Log.Debug(nameof(MainActivity), $"{nameof(OnRestart)}: {this.Id}"); } protectedoverridevoid OnPause() { base.OnPause(); Log.Debug(nameof(MainActivity), $"{nameof(OnPause)}: {this.Id}"); } protectedoverridevoid OnStop() { base.OnStop(); Log.Debug(nameof(MainActivity), $"{nameof(OnStop)}: {this.Id}"); } protectedoverridevoid OnDestroy() { base.OnDestroy(); Log.Debug(nameof(MainActivity), $"{nameof(OnDestroy)}: {this.Id}"); } [Export(nameof(MyButtonClick))] publicvoid MyButtonClick(View v) { this.StartActivity(new Intent(this, typeof(NextActivity))); } } }
ポイントは、OnSaveInstanceStateメソッドとOnCreateメソッドになります。それ以外はボタンが押されたときの画面遷移の処理と、各ライフサイクルメソッドが呼び出されたかログを出力するためのものになります。アプリケーションを実行してMainActivityを表示するとログは以下のようなものが表示されます。
08-20 15:36:59.111 D/MainActivity( 2702): OnCreate: 6986edf6-5759-46a9-98be-4f9185ad23de 08-20 15:36:59.116 D/MainActivity( 2702): OnStart: 6986edf6-5759-46a9-98be-4f9185ad23de 08-20 15:36:59.117 D/MainActivity( 2702): OnResume: 6986edf6-5759-46a9-98be-4f9185ad23de
そして、NextActivityへ遷移すると以下のように表示されます。
08-20 15:37:51.231 D/MainActivity( 2702): OnPause: 6986edf6-5759-46a9-98be-4f9185ad23de 08-20 15:37:52.000 D/MainActivity( 2702): OnSaveInstanceState: 6986edf6-5759-46a9-98be-4f9185ad23de 08-20 15:37:52.001 D/MainActivity( 2702): OnStop: 6986edf6-5759-46a9-98be-4f9185ad23de
そして、戻るボタンでMainActivityに戻ると以下のように表示されます。
08-20 15:39:41.493 D/MainActivity( 2702): OnRestart: 6986edf6-5759-46a9-98be-4f9185ad23de 08-20 15:39:41.493 D/MainActivity( 2702): OnStart: 6986edf6-5759-46a9-98be-4f9185ad23de 08-20 15:39:41.493 D/MainActivity( 2702): OnResume: 6986edf6-5759-46a9-98be-4f9185ad23de
OnDestroyメソッドが呼び出されていないので、Idは保持されたままなのは当然ですよね。次に、実機の開発者オプションで「アクティビティを保持しない」を選択して、疑似的にメモリ不足などでActivityが破棄された時の動作をエミュレートしてみたいと思います。実行してMainActivityが表示されると以下のようなログが出ます。
08-20 15:42:38.221 D/MainActivity(31579): OnCreate: dbc9cedb-a67a-4e61-b6b1-911925fbd001 08-20 15:42:38.223 D/MainActivity(31579): OnStart: dbc9cedb-a67a-4e61-b6b1-911925fbd001 08-20 15:42:38.225 D/MainActivity(31579): OnResume: dbc9cedb-a67a-4e61-b6b1-911925fbd001
そして、NextActivityへ遷移を行います。
08-20 15:43:10.217 D/MainActivity(31579): OnPause: dbc9cedb-a67a-4e61-b6b1-911925fbd001 08-20 15:43:10.667 D/MainActivity(31579): OnSaveInstanceState: dbc9cedb-a67a-4e61-b6b1-911925fbd001 08-20 15:43:10.673 D/MainActivity(31579): OnStop: dbc9cedb-a67a-4e61-b6b1-911925fbd001 08-20 15:43:10.689 D/MainActivity(31579): OnDestroy: dbc9cedb-a67a-4e61-b6b1-911925fbd001
OnDestroyメソッドが呼び出されてMainActivityが破棄されたことが確認できます。この状態で戻るボタンを押してMainActivityに戻ると以下のように表示されます。
08-20 15:44:12.607 D/MainActivity(31579): OnCreate: dbc9cedb-a67a-4e61-b6b1-911925fbd001 08-20 15:44:12.609 D/MainActivity(31579): OnStart: dbc9cedb-a67a-4e61-b6b1-911925fbd001 08-20 15:44:12.624 D/MainActivity(31579): OnResume: dbc9cedb-a67a-4e61-b6b1-911925fbd001
一度MainActivityが破棄されたにも関わらず、Idの値が保持されていることが確認できます。繰り返しますが、画面に置かれた部品でIDが振られたものは自動的に値が保持されるため気にする必要はありませんが、今回のように自分でActivityに一時的に保持しているものは自前で保存と復元を行う必要があります。