しっぽを追いかけて

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

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

Xamarin で Prism の Suspending っぽいイベントを検知したい

スマホアプリの場合、PC よりも少ないリソースで動作するためアプリの状態遷移を考慮した設計が欠かせません

特にリソース不足で OS から強制的に終了する場合に備えてアプリの状態やデータを保存しておき、再起動された際に復帰させるという対応は重要だと思います

f:id:matatabi_ux:20141109133016p:plain

※ 8.1 の場合も基本的に同様ですが、「Dormant → Suspended」、「Tombstoned → Terminated」など上記に対応する状態の名称が変わっています

例えば WIndows Phone 8.0 アプリの場合は、アプリがバックグラウンドに回りリソースが足りなくなると Tombstoned の状態に遷移してデータがメモリから解放されるようです

Tombstoned から Activate されたときに直前に見ていた画面に復帰させたい場合は、バックグラウンドに回った際の Dormant の時点でアプリのデータをファイルに退避しておく必要があります

Prism ではこういった対応を可能にするために、Windows ランタイムアプリにある Suspending イベントが検知できるようになっていて、この Suspending 発生時に必要なデータを保存する処理を記述できるようになっています

Dormant に移行する Application_Deactivated イベントを検知すれば同じようにできそうです*1

/// <summary>
/// アプリケーションクラス
/// </summary>
public partial class App : Application
{
    ~ 中略 ~

    // Code to execute when the application is deactivated (sent to background)
    // This code will not execute when the application is closing
    private void Application_Deactivated(object sender, DeactivatedEventArgs e)
    {
        //TODO:ここに Suspending を通知する処理を記述します
    }
}

App.xaml.cs に最初から Application_Deactivated メソッドがあるのでここに追記できます

f:id:matatabi_ux:20141108210702p:plain

iOS アプリの場合、同じ「Suspended」状態がありますが、これは Windows Phone 8.0 の「Tombstoned」に対応するので、「Background」に移行する際のイベントを検知すれば大丈夫でそうです

/// <summary>
/// アプリケーションクラス
/// </summary>
[Register("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
    ~ 中略 ~

    /// <summary>
    /// Backgroud に移行した際の処理
    /// </summary>
    /// <param name="application">アプリケーションクラス</param>
    public override void DidEnterBackground(UIApplication application)
    {
        base.DidEnterBackground(application);

        //TODO:ここに Suspending を通知する処理を記述します
    }
}

iOS の場合は AppDelegate に DidEnterBackground メソッドを override して追加すればよさそう

問題は Android です・・・

f:id:matatabi_ux:20141109141010p:plain

Android の場合はライフサイクルが画面(Activity)単位で遷移するので、アプリ全体として生きているのかどうかよくわかりません・・・画面の向きを変えただけで Activity の破棄と再生成がされるとかちょっとどうなんだろうと思うほど;

Activity が直接他のアプリの Activity と連携したりするので、アプリの境界があいまいになっているので、いつ開始されたかはわかりやすいですが、いつアプリとしてバックグラウンドになったかはよくわからない仕組みになっているようです

あえて実装するとしたらホームボタンが押されるなどして Activity がバックグラウンドに回ったときに呼び出される onUserLeaveHint() を利用することになるでしょうか

/// <summary>
/// メイン画面
/// </summary>
[Activity(Label = "PrismXamarin", MainLauncher = true, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)] 
public class MainActivity : AndroidActivity 
{
    ~ 中略 ~

    /// <summary>
    /// Backgroud に移行した際の処理
    /// </summary>
    [Android.Runtime.Register("onUserLeaveHint", "()V", "GetOnUserLeaveHintHandler")]
    protected virtual void OnUserLeaveHint ()
    {
        //TODO:ここに Suspending を通知する処理を記述します
    }
} 

実行できないので確信はできませんが、他のアプリより頻繁にデータ退避の処理が走りそうなので効率が悪いですね

*1:Windows Phone 8.1 では退避データからの画面復元もやってくれますが、8.0 では自前でやらなきゃいけないという違いはあります