2011年7月31日日曜日

Life cycle of Windows Phone applications

I found that the application life cycle of Windows Phone applications is not so simple as I expected. Here is a pseudo code to fulfill the requirements. See Execution Model for Windows Phone (http://msdn.microsoft.com/en-us/library/ff769557%28v=vs.92%29.aspx) for details.


private void Application_Launching(object sender, LaunchingEventArgs e)
{
    // Launching to Running state.

    // If application persistent state is available, it should be restored.
    // However, it should not be done here to avoid consuming too much time
    // on launching.
}

private void Application_Activated(object sender, ActivatedEventArgs e)
{
    if (e.IsApplicationInstancePreserved)
    {
        // Activated from Dormant state.
    }
    else
    {
        // Activated from Tombstoned state.

        // Restore the application transient state which was saved
        // during the last call of Application_Deactivated() method.
        var state = PhoneApplicationService.Current.State;
        RestoreApplicationTransientState(state);
    }
}

private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
    // Deactivated to Dormant state.

    // Save the application transient state which may be used later
    // by Application_Activated() method in case this application is
    // relaunched from Tombstoned state.
    var state = PhoneApplicationService.Current.State;
    SaveApplicationTransientState(state);

    // Save the application persistent state to isolated storage
    // because this application may be terminated without being
    // activated, and in such a case, Application_Closing() is
    // not called.
    SaveApplicationPersistentState();
}

private void Application_Closing(object sender, ClosingEventArgs e)
{
    // Save the application persistent state to isolated storage
    // to reuse it later on next invocation.
    SaveApplicationPersistentState();
}


protected override void OnNavigatedTo(NavigationEventArgs e)
{
    // If this page instance is new.
    //
    // The variable _isNewPageInstance here is an instance variable
    // and initialized to true in this page's constructor.
    if (_isNewPageInstance)
    {
        if (0 < State.Count)
        {
            // Activated from Tombstoned state.

            // Use the page state data to build up this page.
            // The data was saved during the last call of
            // OnNavigatedFrom() method which was executed
            // when this application entered Dormant state.
            RestorePageState(State);
        }
        else
        {
            // Normal forward page navigation. Build up this page
            // from scratch.
            InitializePageState(State);
        }

        _isNewPageInstance = false;
    }
    else
    {
        // Activated from Dormant state, or
        // normal page backward navigation.

        // There is nothing to do because the page state remains
        // intact in memory.
    }
}

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
    if (e.NavigationMode == NavigationMode.Back)
    {
        // Normal backward page navigation.

        // No need to save the page state because this page
        // instance is about to be discarded.
    }
    else
    {
        // Save the page state to reuse it later when this
        // application is activated from Tombstoned state.
        SavePageState(State);
    }
}


Windows Phoneアプリケーションのライフサイクル

Windows Phone アプリケーションのライフサイクルは、期待していたほど単純なものではなかった。要求事項を満たすための擬似コードは下記の通り。詳細は Execution Model for Windows Phone (http://msdn.microsoft.com/en-us/library/ff769557%28v=vs.92%29.aspx) を参照のこと。

private void Application_Launching(object sender, LaunchingEventArgs e)
{
    // Launching to Running state.

    // もしもアプリケーションの永続状態が利用可能であれば、復元する。
    // ただし、起動時に多くの時間を消費しないように、復元はここでは
    // おこなわない。
}

private void Application_Activated(object sender, ActivatedEventArgs e)
{
    if (e.IsApplicationInstancePreserved)
    {
        // Activated from Dormant state.
    }
    else
    {
        // Activated from Tombstoned state.

        // 最後の Application_Deactivated() メソッドの呼び出しの際に
        // 保存されたアプリケーションの一時状態を復元する。
        var state = PhoneApplicationService.Current.State;
        RestoreApplicationTransientState(state);
    }
}

private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
    // Deactivated to Dormant state.

    // このアプリケーションが Tombstoned 状態から再起動された場合に
    // Application_Activated() メソッドで使用することになる、アプリ
    // ケーションの一時状態を保存する。
    var state = PhoneApplicationService.Current.State;
    SaveApplicationTransientState(state);

    // Activate されることなくアプリケーションが終了させられることも
    // ありうるので(そのケースでは Application_Closing() は呼ばれない)、
    // アプリケーションの永続状態を isolated storage に保存しておく。
    SaveApplicationPersistentState();
}

private void Application_Closing(object sender, ClosingEventArgs e)
{
    // 次回の起動時に再利用できるよう、アプリケーションの永続状態を
    // isolated storage に保存する。
    SaveApplicationPersistentState();
}

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    // このページインスタンスが新しい場合
    //
    // 変数 _isNewPageInstance はインスタンス変数で、このページの
    // コンストラクタで true に初期化される。
    if (_isNewPageInstance)
    {
        if (0 < State.Count)
        {
            // Activated from Tombstoned state.

            // ページの状態データを使ってこのページを構築する。
            // データは、このアプリケーションが Dormant state に
            // 移行するときに実行された OnNavigatedFrom() メソッド
            // の呼び出し中に保存されたもの。
            RestorePageState(State);
        }
        else
        {
            // 通常の前方ページ遷移。このページを一から構築する。
            InitializePageState(State);
        }

        _isNewPageInstance = false;
    }
    else
    {
        // Activated from Dormant state, もしくは通常の後方ページ遷移。

        // ページの状態はメモリ上にそのまま残っているので、ここでは
        // 特にすることはない。
    }
}

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
    if (e.NavigationMode == NavigationMode.Back)
    {
        // 通常の後方ページ遷移

        // このページインスタンスは破棄されようとしているところなので、
        // ページの状態を保存する必要はない。
    }
    else
    {
        // 後でアプリケーションが Tombstoned 状態から復帰したときに 
        // 再利用するため、ページの状態を保存しておく。
        SavePageState(State);
    }
}