行動大小事

Windows Phone 7 標記刪除

Jaime Rodriguez

下載程式碼範例

好的行動平台應該接受行動性在裝置上強加的硬體限制。與桌上型電腦比起來,行動裝置的記憶體較少,處理能力較弱,畫面項目和電池壽命也較為有限。把這些限制加總起來,結論就是,如果要在一部非專用的裝置上執行許多應用程式,有些應用程式到最後得關閉起來,才能挪出資源供其他應用程式使用。

但是 Windows Phone 可以透過一種叫做標記刪除的功能來應付這項限制。標記刪除看似單純,其實攸關開發人員的競爭力。有些人認為沒必要,有些人認為太困難,也有人單純只是對功能名稱看不順眼。行動裝置限制仍是一個無可避免的問題,因此好的行動應用程式必須能夠掌握標記刪除功能。

Windows Phone 應用程式開發週期

大多數 Windows Phone 開發新手接觸這個平台時,多半認為應用程式的開發週期應該像這樣:

  1. 開始
  2. 執行
  3. 結束
  4. 回到 1,然後重新開始

Windows Phone 7 卻以不同的開發週期來挑戰這種想法,也就是偏向工作階段導向,而非處理程序導向的開發週期。

在 Windows Phone 7 中,您應該把開發週期視為:

  1. 開始
  2. 執行
  3. 中斷執行或結束
  4. 如果中斷了就回來 — 或者中斷了,就重新開始
  5. 如果結束了,就重新開始

這個新工作階段導向模型的優點是,使用者可以不用考慮 OS 如何管理其資源而在不同應用程式間導覽。使用者不在乎為了回覆傳入的 SMS 訊息而中斷遊戲是否會刪除遊戲的處理程序。使用者應該在回覆訊息之後,還是可以回來繼續玩遊戲。如果能夠做到這一點,那麼基本的細微末節就無關緊要了。

但是對開發人員來說,缺點在於他必須多費力處理,才能讓工作階段持續下去,因為您的工作階段仍然是在傳統的處理程序導向 OS 上執行。若要在處理程序導向世界接納工作階段,必須為工作階段建立邏輯狀態:已啟動、已啟用、執行中、已停用、已標記刪除以及已關閉 (或已結束)。

[圖 1] 顯示了 Windows Phone 7 應用程式的實際開發週期。而應用程式開發週期事件 (如 [圖 2] 所示) 是由 Microsoft.Phone.Shell.PhoneApplicationService 類別公開。

[圖 1] Windows Phone 7 應用程式開發週期

[圖 2] 應用程式開發週期事件

邏輯狀態 PhoneApplicationService 事件 說明
已啟動 啟動中 當使用者按下 [開始] 或應用程式清單圖示,或是按一下暫時性通知,即會啟動應用程式。已啟動是指重新開始工作階段。
已啟用 已啟用 當使用者按 [上一步] 按鈕,把先前已停用的應用程式帶回前景時,即會啟用應用程式。這時使用者會預期回到進行中的工作階段。
執行中 執行中 應用程式已啟動或已啟用之後,就處於執行中狀態。
已停用 已停用 當前景處理從這個應用程式轉移到另一個應用程式,或者轉移到一個 OS 元件時 (例如選擇器或啟動程式或鎖定畫面),就會停用執行中的應用程式。這時候工作階段就會中斷,但是稍後應該會繼續執行。
已結束 關閉中

使用者在主頁面按一下 [上一步] 鍵之後,即會結束應用程式。

結束時,使用者會預期回到全新的應用程式。

已標記刪除狀態則稍微複雜,與 PhoneApplicationService 事件並無直接關聯。當應用程式停用時,OS 並不會立即刪除應用程式的處理程序。理論上當 OS 需要資源時,才會刪除應用程式。應用程式並不會接到任何通知,而是直接被刪除。

實際上,當控制權轉移到另一個前景應用程式之後,Windows Phone 7 就會立刻刪除該處理程序,不過這一點不太可靠。Microsoft 已在二月份舉辦的全球行動通訊大展 (Mobile World Congress) 上宣布即將推出「快速應用程式切換」等改良功能,因此不要倚賴實作細節來判斷何時會進行標記刪除,而是應該在停用時做該做的事,準備面對標記刪除。

停用與標記刪除

行動電話隨時隨地都有許多程序 (殼層、電話等) 處於執行狀態,但是前景最多只能執行一個應用程式 (如果前景沒有執行任何應用程式,可能就沒有任何應用程式在執行中)。

當前景應用程式將控制權轉移到另一個應用程式,或轉移到 OS 元件時,就會停用該應用程式。在處理程序停用之後,OS 可能會將它刪除,以釋放資源。這就叫做標記刪除。

正如您所見,不見得每次停用應用程式時都會進行標記刪除,但是標記刪除一定是在停用之後進行。事實上,停用是 PhoneApplicationService 在標記刪除之前所引發的最後一個事件,因此稍後您要再次啟用應用程式時,就必須從該處啟用。

[圖 3] 除了顯示所有會進行停用的工作之外,也同時猜測標記刪除發生的可能性。

[圖 3] 停用工作

動作 會停用嗎? 會標記刪除嗎?
使用者在應用程式的第一頁按 [上一步] 按鈕 不會,這會關閉應用程式 不會,完全不會停用。
使用者按 [開始] 按鈕 很有可能,不過不能保證。應用程式在停用幾秒之後,就會執行標記刪除。如果使用者在停用之後很快又回到應用程式,也許不會執行標記刪除。這個過程可能只會被視為不確定的逾時。
使用者叫用執行標記刪除的選擇器或啟動程式 很有可能,不過也會逾時。
使用者叫用不執行標記刪除的選擇器或啟動程式 可能性較低,不過仍有可能發生。如果使用者在工作中途按了 [開始] 按鈕,就會看到「使用者按 [開始] 按鈕」規則。這時並不會引發新的 Deactivated 事件,因為應用程式已經停用了。
出現鎖定畫面,而應用程式並未設定可在鎖定情況下執行 很有可能,不過也會逾時。
出現暫時性通知,使用者按了它之後,就轉移到另一個前景應用程式 很有可能,不過也會逾時。

有的選擇器不會立刻執行標記刪除,但如果使用者採取了會標記刪除程序的行動,仍有可能會執行標記刪除。這些動作包括 PhotoChooserTask (除非使用者指定裁剪)、CameraCaptureTask、MediaPlayerLauncher、EmailAddressChooserTask 和 PhoneNumberChooserTask。

其他所有的選擇器和啟動程式則會在呼叫 Show 方法之後,立即標記刪除。

若要查看 Windows Phone 7 應用程式開發週期實際的運作狀況,請啟動程式碼下載中的 LWP.TombStoning 範例。

儲存與還原狀態

由於工作階段式導覽的目標是方便使用者順利跳到其他前景應用程式,因此您必須儲存 Deactivated 事件中所有的相關狀態,以及還原 Deactivated 事件中的狀態。大部分的應用程式都有三種要管理的狀態類型:

  • 持續應用程式狀態必須一直持續存在。其中包括應用程式設定、使用者資料等。
  • 工作階段特定應用程式狀態包括快取和 ViewModel 等暫時狀態,這些狀態會在啟用時還原,但如果您重新啟動應用程式時,就會重新開始。
  • 當應用程式啟用時,必須利用 UI 或頁面特定狀態來還原 PhoneApplicationPage。Windows Phone 7 會在執行標記刪除時,儲存應用程式的「上一步」堆疊。當應用程式啟用時,在被刪除標記之前,只會還原前一個作用中的頁面。如果使用者按了 [上一步] 按鈕,前一頁便會執行個體化。

持續應用程式狀態應該會儲存在 IsolatedStorage,或者透過 ApplicationSettings 類別加以儲存。應用程式狀態最好能夠儘早儲存,否則萬一發生電池沒電等狀況就束手無策。

如果是使用者資料 (例如工作階段快取),您就不應該太常執行序列化,應該儲存在 Deactivated 和 Closing 事件,並且 (對稱地) 在 Activated 或 Launching 事件中還原。

如果您希望完全控制序列化格式,或是資料太多,或是可以儲存在 PhoneApplicationService.State 字典中,則可將工作階段專屬的狀態儲存在隔離的存放區內。您只能將它儲存在 Deactivated 事件,並且在 Activated 事件中還原它。

頁面特定狀態則應儲存在 PhoneApplicationPage.State 字典中。儲存頁面狀態的關鍵,是記住應用程式的頁面有「上一步」堆疊,一旦發生 PhoneApplicationService.Deactivated 時,就會自動序列化。為了讓頁面能夠進行標記刪除,您必須接聽頁面中的 PhoneApplicationPage.OnNavigatedFrom 覆寫,並且把尚未交付給 Model (或 ViewModel) 的任何檢視狀態儲存在頁面字典中。別等到 Deactivated 事件發生才做,因為到那時您就無法進入頁面的「上一步」堆疊了。

當然囉,如果您是在收到 OnNavigatedFrom 時儲存頁面狀態,就應該在頁面的 OnNavigatedTo 覆寫中還原它。

您也可以將頁面特定狀態儲存在 ViewModels,然後將 ViewModels 序列化為工作階段狀態,不過這就必須將未認可的狀態儲存在 ViewModel,因此我不建議這麼做。為了達到日後平台最佳化的目標,請妥善運用基礎結構,適應未來情況。

避免易犯錯誤

標記刪除並不困難,只是有點繁瑣,而且必須加以規劃,並且保持一致性。如果您的應用程式已經停用但尚未標記刪除,則狀態會留在記憶體中,不會重新建構。

避免依賴類別建構函式,它會建立應用程式所需的狀態,但是也可能在停用期間被釋出。最好能夠採用對稱方式,對應用程式層級狀態使用 PhoneApplicationService Deactivated 和 Activated 事件,而對頁面狀態使用 OnNavigatedFrom 或 OnNavigatedTo。

如果應用程式中有物件 (單一元素) 是在啟用呼叫之外執行個體化 (可能是因為延遲執行個體化所導致),那麼在使用之前,務必先檢查它們是否有妥善建構和初始化。我常犯的錯誤是讀取 PhoneApplicationService.Activated 事件或 PhoneApplicationPage.OnNavigatedTo 中的資料,但卻沒有重設它。在一個工作階段中,頁面可以多次 NavigatedTo (無論是否有執行標記刪除),甚至工作階段也會多次刪除標記。

在您還原狀態之後,請將它清除。您可以稍後在頁面的 NavigatedFrom 覆寫或應用程式的 Deactivated 事件設定它。

請務必注意您儲存的內容,以及何時還原它。要讓使用者順利回到應用程式,其中一個做法就是立刻還原應用程式。如果頁面或應用程式狀態儲存過於頻繁,就會減慢啟用速度。必要時,請運用隔離的存放區,來存放在應用程式啟用時可能不會馬上用到的背景載入狀態。啟用和停用應該在 10 秒內進行。請務必留意這點,否則 OS 可能會在它完成停用之前或在重新啟用時,刪除您的程序。但是,您必須盡快在 10 秒內完成。

您必須了解序列化架構的限制。在所有的頁面和應用程式狀態當中,您最多可以儲存 2MB 左右。如果總數超過這個數值,那麼在您導覽和停用時,就會開始發生例外狀況。最好不要在頁面狀態中將這麼多資料序列化。如果您需要快取大量資料集,請將它們留在隔離存放區。

請使用查詢字串進行頁面導覽。如果您必須把內容傳到新頁面,請使用已傳到該頁面的查詢字串,將所有資料或唯一識別碼 (語彙基元),傳到可以根據該語彙基元擷取資料的服務定位器。別假設頁面在標記刪除之後再啟用時,還可以使用 ViewModels 或頁面狀態。

您必須了解您的選擇器和啟動程式。它們不見得都會執行標記刪除,而且在為選擇器連接事件接聽程式時,也必須遵守特定的規則。如需參考這些規則,請閱讀bit.ly/edEsGQ. 的<How to:使用 Windows Phone 的選擇器>。

請注意 OnNavigatedTo 和 PhoneApplicationPage.Loaded 之間的關係。OnNavigatedTo 內頁面的視覺化樹狀結構尚未建置完成。您通常必須擷取還原後的狀態,但是必須等到頁面的 Loaded 事件後才能還原 UI 狀態。必須延遲的動作,包括捲動、設定 Focus,以及在樞紐中設定 SelectedIndex 等都是。

如果您在不需要時卻花了很多精力在儲存和還原資料上,不妨考慮一些進階的最佳化方法。不過請注意,您只有在必要時才能這麼做,而且務必經過徹底測試才行。

如果要偵測標記刪除,請在停用時,在應用程式類別設定一個旗標。如果啟用時沒有重設旗標,就表示您並未標記刪除,所有的頁面應該仍在記憶體中,而無需還原。如果要在頁面中將它與偵測標記刪除結合起來,可以在工作階段內,針對每一次啟動各使用一個語彙基元。

另一種最佳化方法是接聽頁面的 OnNavigatingFrom 覆寫,並且偵測方向。如果 NavigationMode 往回走,頁面就會銷毀,因此您也不必為它儲存狀態。

同樣的,要妥善執行標記刪除,規劃是非常重要的一環。別等到應用程式開發週期快結束時才執行標記刪除,並試圖修改。一定要盡早規劃,按照計劃執行,並且徹底測試。

您可以將它發揚光大

我給開發人員的最後一個秘訣就是,努力思考如何讓過程順利執行。Windows Phone 7 控制項可讓您輕鬆在頁面移動。如果要為使用者提供真正的順暢體驗 — 感覺好像從未離開頁面或應用程式 — 應該考慮還原下列各項:

  • 樞紐的 SelectedIndex (如果頁面含有樞紐)
  • ListBox 中的捲動位置,或是頁面中其他任何的 ScrollViewer
  • 地圖控制項、圖片檢視器或其他任何支援操作之控制項中的縮放層級及其他轉換
  • TextBox 中未認可的文字;如果 TextBox 對於應用程式來說非常重要 (例如,Twitter 應用程式中的 tweet 文字),請考慮還原文字選擇、插入點位置以及焦點
  • 頁面中焦點所在的元素 (尤其如果它是需要顯示 SIP 的 TextBox)

您不應該還原的是全景中的 SelectedItem。全景不支援這一項,而且在全景中設定 DefaultItem,與取景到正確的頁面是不一樣的。我建議您避免使用 DefaultItem 回到在標記刪除前選取的全景項目。

若要查看這些秘訣實際的操作方式,請啟動程式碼下載中的 LPW.TombstoningWithState 範例。readme.txt 檔案中的每一個案例都有指標和指令碼。

結語

本文絕非標記刪除的完整參考文章。但既然您已知道要注意哪些事項,不妨開始將部分標記刪除模式導入自己的 Windows Phone 7 應用程式中,相信您馬上可以目睹到它提升使用者體驗的效果。

Jaime Rodriguez 在 Microsoft 擔任推廣人員主管,負責推動採用 Silverlight 和 Windows Phone 7 等新興的用戶端技術。您可以在 Twitter (twitter.com/jaimerodriguez) 找到他,也可以閱讀他的部落格 (blogs.msdn.com/jaimer)。

感謝以下協助校閱本篇文章的技術專家:Peter Torr