Windows Phone 8.1 - 操作 App Lifecycle

Windows Phone 8.1 - 操作 App Lifecycle

在<Windows Phone 8.1 - Application lifecycle 概念>介紹了相關 XAML App 新 Lifecycle之後,

接著該篇將說明怎麼在 Lifecycle 中保存與還原 App 裡使用到的資料。

 

再複習一次這一篇重要的圖示:

IC576232_thumb[2]

 

針對這張圖搭配 App 的幾個重要事件來說明:

 

A. 負責處理 App 啟動的事件

a-1. Override launch handler

    不管任何理由當 App 被啟動時,系統會發送一個 Activated 事件。透過覆寫 OnLaunchHandler 來得知是什麼方式啟動。

    藉由「ActivationKind」列舉得知有那些啟動類型,如下圖說明:

    image

    image

    image

    需注意有些項目有分「Windows Store Only 與 Windows Phone Only」。

    另外,「Windows.UI.Xaml.Application」定義多種可被覆寫的 OnActivated 方法互相配合。

    藉由覆寫 OnLaunched 方法補捉用戶啟動 App 的時機,並使用 LaunchActivatedEventArgs  取得啟動參數與 App 之前的狀態

    [注意]

    a. OnLaunched 方法在 Windows Phone 環境,當用戶透過 Start tile 或 App list 啟動該 App 均會被觸發,即使 App 在記憶體

        中為 Suspended 狀態也是

    b. OnLaunched 方法在 Windows Store 環境,當 App 存在記憶體中為 Suspended 時,用戶透過 Start tile 或 App list 均不會啟動

 

 

a-2. Restore application data if app was suspended then terminated

    當用戶選擇開啟已被 Terminated 的 App 後,系統會通知 Activated event 設定 Launch 的 Kind 的值為 Launch 與指定 PreviousExecutionState

    為 Terminated 或 ClosedByUser。此時,App 應該載入儲存的 application data 與更新畫面中的內容。如果 PreviousExecutionState 的值為:

    NotRunning 的話,代表 App 可能發現 Crash 或是其他狀態,那麼 App 應該回到剛啟動應用程式的狀態,初始化所有需要的值。

async protected override void OnLaunched(LaunchActivatedEventArgs args)
{
   if (args.PreviousExecutionState == ApplicationExecutionState.Terminated ||
       args.PreviousExecutionState == ApplicationExecutionState.ClosedByUser)
   {
      // TODO: Populate the UI with the previously saved application data
   }
   else
   {
      // TODO: Populate the UI with defaults
   }
 
   EnsurePageCreatedAndActivate();
}

    (如果 NotRunning 不處理,App 卻有邏輯是需要依賴 restore 的資料時,那可能會出現永遠 crash 的狀態,因為 restore 的資料是錯的,

    建議可以增加處理 NotRunning 來還原資料)

 

    [注意]

    〉在 Windows Phone,當 App 正在 suspended 或 re-launched 隨著用戶點擊 primary tile 或 app list 開啟時,Resuming event 永遠在

        OnLaunched event之後。可以搭配「LaunchActivatedEventArgs.TileId 」來決定 App 從 primary tile 或 secondary tiles 啟動時,

        是否需要保持離開前的狀態或是重新來過。

 

 

 

B. 負責處理 App 進入暫停的事件

b-1. Register the suspending event handler

        註冊 Suspending event 處理在 App 被系統 suspends 前把重要的資料保存起來。

partial class MainPage
{
   public MainPage()
   {
      InitializeComponent();
      Application.Current.Suspending += new SuspendingEventHandler(App_Suspending);
   }
}

 

 

b-2. Save application data before suspension

         在保存資料時,可透過 File、ApplicationData、Roaming Data 或是 SuspendingManager 的功能將保存的物件序列化成檔案…等;

partial class MainPage
{
    async void App_Suspending(
        Object sender, 
        Windows.ApplicationModel.SuspendingEventArgs e)
    {
        // TODO: This is the time to save app data in case the process is terminated
    }
}

在此介紹簡單相關的 ApplicationData 相關類別的使用

 

ApplicationData

    提供存取應用程式資料的類別,包括:App 資料夾(local、roaming、temporary…)、檔案與設定…等。如下列舉:

Property Access type Description
Current Read-only Provides access to the app data store associated with the app's app package.
LocalFolder Read-only Gets the root folder in the local app data store.
LocalSettings Read-only Gets the application settings container in the local app data store.
RoamingFolder Read-only Gets the root folder in the roaming app data store.
RoamingSettings Read-only Gets the application settings container in the roaming app data store.
RoamingStorageQuota Read-only Gets the maximum size of the data that can be synchronized to the cloud from the roaming app data store.
TemporaryFolder Read-only Gets the root folder in the temporary app data store.
Version Read-only Gets the version number of the application data in the app data store.

     如果需要存取 App 安裝目錄下的檔案,請使用:Windows.ApplicationModel.Package.InstalledLocation

 

 

b-3. Release exclusive resources and file handles:

        App 進入 Suspending event 時,除了要保存資料之外,可建議在這個時候將使用到的資源或存取中的檔案加以釋放,

例如:相機功能的存取、檔案占用、外部設備連接、網路資源…等,這樣有助於其他程式可以存取他們。等到 App 又重新被啟動時,

再重新取得連線與資源的存取。

 

[注意]

1. 當 App 剛被系統暫停後例如:用戶切換至另一個程式或回到開始畫面),如果用戶又馬上切回到 App,

    App 中使用的變數與資料結構還是跟離開前的一樣,是不需特別做什麼事情的。

2. 當 App 被系統暫停後,系統僅是使用有限的記憶體空間保存該 App,但是當系統發現記憶體不夠用時,它會將暫停的 App 終結掉。

    此時,用戶再切換回 App 時,App 使用的變數與資料結構將消失,此時就需要 App 實作 OnLaunched 來還原資料;

3. 由於 App 由暫停至系統終結,App 本身不會收到任何事件,所以需要在觸發 Suspending event 時將資料保存;

4. 如果在 Suspending event 內處理的需要有非同步或較長的時間,記得運用 「SuspendingOperation.GetDeferral()」

    取得加長時間的請求,等到完成後再呼叫「Complete」宣告已完成;

5. 注意用 Visual studio Debug 時,需要藉由「Location toolbar」上的 Suspend icon 來觸發 Suspending event;

6. Windows 8.1 在 suspending event 內的邏輯時間不可超過 5 秒;

    Windows Phone 8.1 介於 1 ~ 10 秒之間;

 

 

 

C. 處理 App 由暫停狀態重新回到執行狀態 (Resume)

c-1. Register the resuming event handler

        註冊 Resuming event 負責還原 App 返回後,需要更新的內容與擷取網路資源的任務。

partial class MainPage
{
   public MainPage()
   {
      InitializeComponent();
 
      // 在畫面註冊 Resuming 事件來處理當 Page 返回時可對 UI 做一些處理
      Application.Current.Resuming += new EventHandler<Object>(App_Resuming);
   }
}

       

 

c-2. Refresh displayed content after suspension

        藉由在 Page 註冊 Resuming event 來處理畫面的呈現與資料的 binding。

但是要注意:Resuming event 不是從 UI thread 衍生的,所以沒有辦法直接操作 UI 上的物件,需要搭配:dispatcher,來操作

partial class MainPage
{
    private void App_Resuming(Object sender, Object e)
    {
        // TODO: Refresh network data
    }
}

 

 

 

D. 處理 Back button (只有 WP)

    過去在 Silverlight App 開發的 Windows Phone App,當用戶按下 Back 按鈕時,如果 Navigation Stack 有其他 Page 系統將會自動退回上一頁。

但是 XAML App 開始將與 Store App 相同,按下 Back 按鈕後 App 會進入 Suspend 的狀態,畫面退回至 Start Screen 或另一個 App

為了讓用戶有一致的操作體驗,在開發 XAML App 時需要針對 「BackPressed event」進行處理

   

* BackPressed event

    監聽該事件的觸發,搭配「BackPressedEventArgs.Handled」屬性值的設定,舉例來說:如果預計該 App 在第二個 Page 時,

    用戶按下了 Back button,希望退回到第一個 Page,那麼就應該設定「BackPressedEventArgs.Handled = true」代表 Back button 的事件已經

    被處理完畢不需要再往上一層通知處理。相反地,如果希望 App 進入 Suspend 的狀態那就不要設定該值。

    如下 App.xaml.cs 提供的範例<Handling the Back Button in a Windows Phone app (XAML)>:

public App()
{
    this.InitializeComponent();
    this.Suspending += this.OnSuspending;
 
    // 註冊要處理 Back Button 的事件邏輯。
    Windows.Phone.UI.Input.HardwareButtons.BackPressed += HardwareButtons_BackPressed;
}
 
void HardwareButtons_BackPressed(object sender, Windows.Phone.UI.Input.BackPressedEventArgs e)
{
    Frame frame = Window.Current.Content as Frame;
    if (frame == null)
    {
        return;
    }
 
    if (frame.CanGoBack)
    {
        frame.GoBack();
        e.Handled = true;
    }
}

    如果您僅需要在某幾個 Page 需要處理 BackPressed Event,也可以直接在 Page 的建構子時加入 HardwareButtons.BackPressed 的處理。

 

由於 App 被啟動可以來自各種原因 (點擊 primary / secondary tile,toast notification,file 或 URI associations … 等),

Back button 的任務應該是帶著用戶經過他們瀏覽過的歷程,所以需要考量以下幾點:

 

a. 用戶開啟 App 是透過 primary tile 進入,看到 default start page 然後繼續往 App 中其他 Page 瀏覽;

b. 用戶按下 Start Button 然後開啟其他 App,再按 Start Button 回到 Start Screen;

c. 用戶藉由 secondary tiles 進入 App,利用 deep link 開啟指定的 Page;

d. 用戶按下 Back Button;

 

藉由這四點來看,當用戶按下 Back Button 時,在 c 的狀態應該回到 Start Screen,因為這樣才會符合用戶的期待 (符合過去 WP7.x 或 WP 8.0 的操作體驗),

不應該讓他們可以導回其他歷程中的 Page,這樣會讓用戶搞混 Back Button 的用途。

另外,可參考以下幾點官方的說明來設計 App 中 suspend 與 resume的行為處理:

 

 

〉Do

    =>Handle the Back button if you want to navigate inside your app

          註冊處理 Back Button 來關閉例如:message boxes、menu …等畫面中額外加入的項目;

          也要處理 Navigate 到之前的 Page 邏輯;

 

    =>Ensure proper Back button behavior when your app supports multiple launch points

          如果啟動點多元時,可以試著保存啟動時的參數,在每一次啟動時比對是否一致或其他邏輯,

          如果參數二次是不一致,可試著重新建立一個新的 navigation history,例如:建立一個新的 Frame 來保存第一頁,

          快速退回到到需要的頁面。

          如果要保存低的記憶體用量,則是在 App 進入 Suspend 時不要保存 navigation history,一律視為從 primary tile 啟動 App;

 

〉Don’t

    =>Don’t handle the BackPressed event on your app’s top page:

          當 App 目前正處理最上層的一頁(或 navigation history 為空)時,不要再註冊處理 BackPressed 事件,請交給系統的事件來處理;

 

    =>Don’t allow your app to go over memory limits because of too many navigation history instances.:

          監控 App 的記憶體與保持 navigation history 只有一組,以避免在記憶體中存放多種 navigation history 造成浪費;

 

 

[補充]

Window class

    表示應用程式視窗。與 Application 屬性的用法相似, Content 屬性將會回傳一個 app window object。

重要事件、屬性與方法:

類型 名稱 描述
Event Activated Occurs when the window has successfully been activated.
  Closed Occurs when the window has closed.
  SizeChanged Occurs when the app window has first rendered or has changed its rendering size.
  VisibilityChanged Occurs when the value of the Visible property changes.
Method Activate Attempts to activate the application window by bringing it to the foreground and setting the input focus to it.
  Close Closes the application window.
Properties Content Read/write,Gets or sets the visual root of an application window.
  Current Read-only,Gets the currently activated window for an application.
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
    // Create a Frame to act navigation context and navigate to the first page
    var rootFrame = new Frame();
    rootFrame.Navigate(typeof(BlankPage));
 
    // Place the frame in the current Window and ensure that it is active
    Window.Current.Content = rootFrame;
    Window.Current.Activate();
}

 

 

Application class

    封裝了應用程式和其可用的服務。App 中的 App.xaml.cs 即時繼承了該類別。做為管理整個 App 的一個主要介值。

重要事件:

Event Description
Resuming Occurs when the application transitions from Suspended state to Running state.
Suspending Occurs when the application transitions to Suspended state from some other state.
UnhandledException Occurs when an exception can be handled by app code, as forwarded from a native-level Windows Runtime error. Apps can mark the occurrence as handled in event data.

 

重要方法:

Method Description
Exit Shuts down the app.
OnActivated Invoked when the application is activated by some means other than normal launching.
OnCachedFileUpdaterActivated Invoked when the application is activated due to an activation contract with ActivationKind as CachedFileUpdater.
OnFileActivated Invoked when the application is activated through file-open.
OnFileOpenPickerActivated Invoked when the application is activated through file-open dialog association.
OnFileSavePickerActivated Invoked when the application is activated through file-save dialog association.
OnLaunched Invoked when the application is launched. Override this method to perform application initialization and to display initial content in the associated Window.
OnSearchActivated Invoked when the application is activated through a search association.
onShareTargetActivated Invoked when the application is activated through sharing association.
OnWindowCreated Invoked when the application creates a window.
Start Provides the entry point and requests initialization of the application. Use the callback to instantiate the Application class.

======

學習 WP 8.1 XAML App 開發應該最多不習慣的就是過去 Silverlight App 的週期到現在均不適用。

所以需要重新思考 App 的開發方式與狀態保存的時機點。但相對於過去的開發方式,App 獲得了更多的資源這是非常棒的。

希望該篇有幫助到學習 WP 8.1 的人,謝謝。

 

References:

Roadmap for Windows Runtime apps using C# or Visual Basic (學習地圖)

Windows Phone Store APP Lifecycle and Background Processing

Launching, resuming, and multitasking (XAML)

How to activate an app (XAML)

How to suspend an app (C#/VB/C++)

How to resume an app

Application lifecycle (Windows Runtime apps)

Guidelines for app suspend and resume

Developing apps (XAML) (學習)

App contracts and extensions (Windows Runtime apps) (其他啟動 App 的方式與契約)

Handling the Back Button in a Windows Phone app (XAML)

 

Dotblogs Tags: ,