しっぽを追いかけて

ぐるぐるしながら考えています

Unity と猫の話題が中心   掲載内容は個人の私見であり、所属組織の見解ではありません

Xamarin.Forms の App Lifecycle の呼び出され方を調べたい 【Android 編】

今回は一番厄介そうな Xamarin.Android のアプリケーションライフサイクルの動作を確かめてみたいと思います

まずは Android のアプリケーション状態遷移のおさらい

Google 公式の資料を見ると

http://developer.android.com/images/activity_lifecycle.png

Android は画面ごとに状態遷移する上にめちゃくちゃ細かい

・・・ざっくりととらえるなら

f:id:matatabi_ux:20150308083355p:plain

こんな感じでしょうか Paused と Stopped の違いが分かりにくいですが、Stopped してしまうと復帰に必要なデータや手順が増えるものと思います

上記を踏まえて Android の動作確認用のアプリを作ります

とりあえずブラウザを開く機能を追加

/// <summary>
/// Web ブラウザを開くサービス
/// </summary>
public class OpenBrowserService : IOpenBrowserService
{
    /// <summary>
    /// Web ブラウザを開く
    /// </summary>
    /// <param name="uri">Uri</param>
    public void OpenUri(string uri)
    {
        SimpleLogger.WriteLine(string.Format("open to {0}", uri));

        Forms.Context.StartActivity(new Intent(Intent.ActionView, global::Android.Net.Uri.Parse(uri)));
    }
}

ブラウザを開くインテントを作り新規アクティビティを起動させるみたいです

次に MainActivity.cs を変更

/// <summary>
/// メイン Activity
/// </summary>
[Activity(Label = "SupportLifecycle", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation, LaunchMode = LaunchMode.Multiple)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
{
    /// <summary>
    /// Create イベントハンドラ
    /// </summary>
    /// <param name="bundle">起動情報</param>
    protected override void OnCreate(Bundle bundle)
    {
        SimpleLogger.WriteLine("OnCreate.");

        // ブラウザで開く機能を登録
        App.Container.RegisterType<IOpenBrowserService, OpenBrowserService>(new ContainerControlledLifetimeManager());

        base.OnCreate(bundle);

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

    /// <summary>
    /// Start イベントハンドラ
    /// </summary>
    protected override void OnStart()
    {
        SimpleLogger.WriteLine("OnStart.");

        base.OnStart();
    }

    /// <summary>
    /// RestoreInstanceState イベントハンドラ
    /// </summary>
    /// <param name="savedInstanceState">一時保存情報</param>
    protected override void OnRestoreInstanceState(Bundle savedInstanceState)
    {
        SimpleLogger.WriteLine("OnRestoreInstanceState.");

        base.OnRestoreInstanceState(savedInstanceState);
    }

    /// <summary>
    /// PostCreate イベントハンドラ
    /// </summary>
    /// <param name="savedInstanceState">一時保存情報</param>
    protected override void OnPostCreate(Bundle savedInstanceState)
    {
        SimpleLogger.WriteLine("OnPostCreate.");

        base.OnPostCreate(savedInstanceState);
    }

    /// <summary>
    /// Resume イベントハンドラ
    /// </summary>
    protected override void OnResume()
    {
        SimpleLogger.WriteLine("OnResume.");

        base.OnResume();
    }

    /// <summary>
    /// PostResume イベントハンドラ
    /// </summary>
    protected override void OnPostResume()
    {
        SimpleLogger.WriteLine("OnPostResume.");

        base.OnPostResume();
    }

    /// <summary>
    /// UserLeaveHint イベントハンドラ
    /// </summary>
    protected override void OnUserLeaveHint()
    {
        SimpleLogger.WriteLine("OnUserLeaveHint.");

        base.OnUserLeaveHint();
    }

    /// <summary>
    /// SaveInstanceState イベントハンドラ
    /// </summary>
    /// <param name="outState">出力情報</param>
    protected override void OnSaveInstanceState(Bundle outState)
    {
        SimpleLogger.WriteLine("OnSaveInstanceState.");

        base.OnSaveInstanceState(outState);
    }

    /// <summary>
    /// CreateThumbnail イベントハンドラ
    /// </summary>
    /// <param name="outBitmap">出力画像</param>
    /// <param name="canvas">出力先</param>
    /// <returns>サムネイル生成結果</returns>
    public override bool OnCreateThumbnail(Bitmap outBitmap, Canvas canvas)
    {
        SimpleLogger.WriteLine("OnCreateThumbnail.");

        return base.OnCreateThumbnail(outBitmap, canvas);
    }

    /// <summary>
    /// Pause イベントハンドラ
    /// </summary>
    protected override void OnPause()
    {
        SimpleLogger.WriteLine("OnPause.");

        base.OnPause();
    }

    /// <summary>
    /// NewIntent イベントハンドラ
    /// </summary>
    protected override void OnNewIntent(Intent intent)
    {
        SimpleLogger.WriteLine("OnNewIntent.");

        base.OnNewIntent(intent);
    }

    /// <summary>
    /// Restart イベントハンドラ
    /// </summary>
    protected override void OnRestart()
    {
        SimpleLogger.WriteLine("OnRestart.");

        base.OnRestart();
    }

    /// <summary>
    /// Stop イベントハンドラ
    /// </summary>
    protected override void OnStop()
    {
        SimpleLogger.WriteLine("OnStop.");

        base.OnStop();
    }

    /// <summary>
    /// Destroy イベントハンドラ
    /// </summary>
    protected override void OnDestroy()
    {
        SimpleLogger.WriteLine("OnDestroy.");

        base.OnDestroy();
    }
}

DI コンテナに先ほどのサービスクラス実体を登録するのと、各種状態遷移のイベントハンドラをログ出力つきで追加しました・・・多すぎる;

LauchMode は変に使いまわしされないように Multiple にして下記の操作を実行してみます

  • アプリ起動
  • 画面の向きを回転(2回)
  • 次画面に遷移
  • ブラウザで Xamarin ホームを開く
  • アプリに戻る
  • トップ画面に戻る
  • OS ホームに戻る
  • 再度アプリに戻る
  • アプリを終了
  • 再度起動

画面単位で状態遷移するので画面の向きの回転も入れてみました

操作の様子はこんな感じ

f:id:matatabi_ux:20150308111804g:plain

出力されたログは・・・

App.OnStart: started.
MainActivity.OnStart: OnStart.
MainActivity.OnPostCreate: OnPostCreate.
MainActivity.OnResume: OnResume.
MainActivity.OnPostResume: OnPostResume.
TopPage.xaml.OnAppearing: TopPage Appearing.
SecondPage.xaml.OnAppearing: SecondPage Appearing.
OpenBrowserService.OpenUri: open to http://www.xamarin.com
MainActivity.OnUserLeaveHint: OnUserLeaveHint.
MainActivity.OnPause: OnPause.
MainActivity.OnSaveInstanceState: OnSaveInstanceState.
MainActivity.OnStop: OnStop.
App.OnSleep: sleeped.
MainActivity.OnRestart: OnRestart.
App.OnResume: resumed.
MainActivity.OnStart: OnStart.
App.OnResume: resumed.
MainActivity.OnResume: OnResume.
MainActivity.OnPostResume: OnPostResume.
TopPage.xaml.OnAppearing: TopPage Appearing.
MainActivity.OnUserLeaveHint: OnUserLeaveHint.
MainActivity.OnPause: OnPause.
MainActivity.OnSaveInstanceState: OnSaveInstanceState.
MainActivity.OnStop: OnStop.
App.OnSleep: sleeped.
MainActivity.OnRestart: OnRestart.
App.OnResume: resumed.
MainActivity.OnStart: OnStart.
App.OnResume: resumed.
MainActivity.OnResume: OnResume.
MainActivity.OnPostResume: OnPostResume.
MainActivity.OnUserLeaveHint: OnUserLeaveHint.
MainActivity.OnPause: OnPause.
MainActivity.OnSaveInstanceState: OnSaveInstanceState.
MainActivity.OnStop: OnStop.
App.OnSleep: sleeped.

やっぱり呼ばれるイベントハンドラが多い・・・Xamarin の中の人が頑張ったのか、初回起動でなぜか MainActivity.OnResume が呼ばれますが、App.OnResume は呼ばれません

画面を回転しても onDestroy、onCreate は呼ばれませんでした

どうも Xmarin.Forms の Page は Fragment らしく、画面遷移しても Activity は増えない様子・・・まだ Android に触り始めたところなので間違っているかもしれませんが;

このあたりは API Level の設定や機種によっても変わるのでしょうか・・・おそろしや;

まぁとにかく Xamarin.Forms の App.OnResume でセッションデータを復元すれば基本的に大丈夫でそうですね