SIN@SAPPOROWORKSの覚書

C#を中心に、夜な夜な試行錯誤したコードの記録です。

Xamarin.Forms ライフサイクル

【 Xamarin 記事一覧 】

ライフサイクル

Xamarin.Forms 1.3において新しく刷新した、Xamarin.Forms.Applicationクラスには、次の3つのメソッドがオーバーライド可能になりました。

OnStart アプリのスタート時
OnSleep アプリがバックグランド(スリープ状態)に移行した時
OnResume アプリがバックグランド(スリープ状態)から復帰した時

この動作について、詳細なレポートが@matatabi_uxさんの所で紹介されています。

Xamarin.Forms の App Lifecycle の呼び出され方を調べたい - しっぽを追いかけて
Xamarin.Forms の App Lifecycle の呼び出され方を調べたい 【Windows Phone 8.0 編】 - しっぽを追いかけて
Xamarin.Forms の App Lifecycle の呼び出され方を調べたい 【iOS編】 - しっぽを追いかけて
Xamarin.Forms の App Lifecycle の呼び出され方を調べたい 【Android 編】 - しっぽを追いかけて

上記のページで、全然、完璧なのですが、もともとiOSやAndroidのライフサイクルについて知識の乏しい私が理解するにはちょっと重たかったので・・・
完全真似っこですが、私なりに確かめてみました。

動作確認用のコード

動作確認のために書いたコードは下記の通りです。
ナビゲーションページをルートとして1ページ目をライム色、2ページ目をピンク色にしました。
また、1ページ目には、2ページ目に移動するボタンと、ブラウザを開くボタンを配置しました。

通過したメソッドを確認するためには、Appクラスに、呼び出し元のクラス名及びメソッド名を出力するLog()を作成し、オーバライドした各メソッドからこれを呼び出すようにしました。

//App.cs
namespace App1{
    public class App : Application{
        public App(){
            //NavigationPageの上に最初のページを構築する
            MainPage = new NavigationPage(new TopPage());
        }

        protected override void OnStart(){
            Log();//ログ出力
        }

        protected override void OnSleep(){
            Log();//ログ出力
        }

        protected override void OnResume(){
            Log();//ログ出力
        }

        //呼び出し元のメソッド名を出力のする 「クラス名.メソッド名()」の形式
        public static void Log([CallerFilePath] string file = "", [CallerMemberName] string member = ""){
            Debug.WriteLine(string.Format("{0}.{1}()", Path.GetFileNameWithoutExtension(file).Split('\\').LastOrDefault(), member));
        }

    }

}

//最初のぺージ TopPage.cs
namespace App1{
    class TopPage : ContentPage{
        public TopPage(){
            BackgroundColor = Color.Lime;//背景色(ライム)

            //次ぼページ(SecondPage)を開くボタン
            var button1 = new Button{
                Text = "Next",
                Command = new Command(async () =>{
                    await Navigation.PushAsync(new SecondPage());
                })

            };
            //ブラウザを開くボタン
            var button2 = new Button{
                Text = "Browser",
                Command = new Command(() =>{
                    Device.OpenUri(new Uri("http://xamarin.com/"));
                })

            };
            //2つのボタンを上下に配置する
            Content = new StackLayout{
                Children = { button1, button2 }
            };
        }

        protected override void OnAppearing(){
            App.Log();//ログ出力
            base.OnAppearing();
        }
    }
}

//2つ目のページ SecondPage.cs
namespace App1{
    class SecondPage : ContentPage{
        public SecondPage(){
            BackgroundColor = Color.Pink;//背景色(ピンク)
        }
        protected override void OnAppearing(){
            App.Log();//ログ出力
            base.OnAppearing();
        }
    }
}



Androidでの実行画面
f:id:furuya02:20150403000800p:plain:w400
iOSでの実行画面
f:id:furuya02:20150403000757p:plain:w400
WindowsPhoneでの実行画面
f:id:furuya02:20150403000759p:plain:w400


iOSによる動作確認

AppDelegate.csでも、各メソッドをオーバーライドしてLog()をコールしました。

namespace App1.iOS{
    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate{
        public override bool FinishedLaunching(UIApplication app, NSDictionary options){
            global::Xamarin.Forms.Forms.Init();
            LoadApplication(new App());

            App.Log();//ログ出力

            return base.FinishedLaunching(app, options);
        }

        public override void FinishedLaunching(UIApplication application) {
            App.Log();//ログ出力
            base.FinishedLaunching(application);
        }

        ・・・省略・・・

アプリ起動

f:id:furuya02:20150403001442p:plain:w150:leftAppDelegate.WillFinishLaunching() //起動時に呼び出される
AppDelegate.FinishedLaunching() //はじめての起動時に呼び出される
App.OnStart()
AppDelegate.OnActivated() // アクティブ化
TopPage.OnAppearing() // 表示

ページ遷移

f:id:furuya02:20150403001623p:plain:w200:leftSecondPage.OnAppearing()// 表示

ページ復帰

f:id:furuya02:20150403001826p:plain:w200:leftTopPage.OnAppearing()// 表示

ブラウザ起動

f:id:furuya02:20150403001846p:plain:w200:leftAppDelegate.OnResignActivation() //アプリが非Activeになる直前に呼び出される
App.OnSleep()
AppDelegate.DidEnterBackground() //アプリが非Activeになりバックグランド実行になった際に呼び出される

ホーム

f:id:furuya02:20150403001911p:plain:w200:leftAppDelegate.OnResignActivation() //アプリが非Activeになる直前に呼び出される
App.OnSleep()
AppDelegate.DidEnterBackground() //アプリが非Activeになりバックグランド実行になった際に呼び出される

タスクリストからの起動

f:id:furuya02:20150403011536p:plain:w200:leftAppDelegate.WillEnterForeground()
App.OnResume()
AppDelegate.OnActivated()

タスクリストへの移行

f:id:furuya02:20150403001932p:plain:w200:leftAppDelegate.OnResignActivation() //アプリが非Activeになる直前に呼び出される
App.OnSleep()

アプリ終了

f:id:furuya02:20150403001954p:plain:w150:leftAppDelegate.DidEnterBackground() //アプリが非Activeになりバックグランド実行になった際に呼び出される
AppDelegate.WillTerminate() //システムからのアプリ終了の際に呼び出される


Androidによる動作確認

MainActivity.csでも、各メソッドをオーバーライドしてLog()をコールしました。

namespace App1.Droid{
    [Activity(Label = "App1", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity{
        protected override void OnCreate(Bundle bundle){
            base.OnCreate(bundle);

            global::Xamarin.Forms.Forms.Init(this, bundle);
            LoadApplication(new App());

            App.Log();//ログ出力
        }

        protected override void OnStart() {
            App.Log();//ログ出力
            base.OnStart();
        }

        protected override void OnRestoreInstanceState(Bundle savedInstanceState) {
            App.Log();//ログ出力
            base.OnRestoreInstanceState(savedInstanceState);
        }
        
        ・・・省略・・・

アプリ起動

f:id:furuya02:20150403002304p:plain:w100:leftApp.OnStart()
MainActivity.OnCreate()
MainActivity.OnStart()
MainActivity.OnPostCreate()
MainActivity.OnResume()
MainActivity.OnPostResume()
TopPage.OnAppearing()

ページ遷移

f:id:furuya02:20150403002419p:plain:w200:leftSecondPage.OnAppearing()

ページ復帰

f:id:furuya02:20150403002438p:plain:w200:leftTopPage.OnAppearing()

ブラウザ起動

f:id:furuya02:20150403002452p:plain:w200:leftMainActivity.OnUserLeaveHint()
MainActivity.OnPause()
MainActivity.OnSaveInstanceState()
MainActivity.OnStop()
App.OnSleep()

ブラウザからの復帰

f:id:furuya02:20150403002507p:plain:w200:leftMainActivity.OnRestart()
App.OnResume()
MainActivity.OnStart()
App.OnResume()
MainActivity.OnResume()
MainActivity.OnPostResume()

ホーム

f:id:furuya02:20150403002523p:plain:w200:leftMainActivity.OnUserLeaveHint()
MainActivity.OnPause()
MainActivity.OnSaveInstanceState()
MainActivity.OnStop()
App.OnSleep()

タスクリストからの起動

f:id:furuya02:20150403010949p:plain:w200:left
MainActivity.OnRestart()
App.OnResume()
MainActivity.OnStart()
App.OnResume()
MainActivity.OnResume()
MainActivity.OnPostResume()

タスクリストへの移行

f:id:furuya02:20150403002535p:plain:w200:left
ログなし(おそらくこの時点ではActive)


アプリ終了

f:id:furuya02:20150403002550p:plain:w100:left
ログなし(既にHomeに遷移した時点でOnStopとなっているから)



サンプル

github.com



【 Xamarin 記事一覧 】