WINDOWS 10 2015 年特別版
此文章由機器翻譯。
# 應用生命周期 - 通過后臺任務和擴展執行使應用處于活動狀態
通過?[Shawn Henry](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Shawn+Henry)?|Windows 2015 年
它用于將應用程序的生命周期很容易。當用戶啟動應用程序時,它無法瘋狂的系統上運行: 消耗資源、 彈出窗口,并通常執行它而不考慮其他人高興。如今,事情要更棘手。在移動優先世界中,應用程序被限制為定義的應用程序生命周期。此生命周期指定當應用程序可以運行,但大多數情況下它不能 — 如果應用程序不是當前用戶執行的操作,它不允許運行。
在大多數情況下,這是很好 — 用戶知道已應用程序不是在消耗能量或采用削弱性能。對于應用程序,操作系統什么一直都很好的做法,應用程序進入停止穩定狀態在不活動的使用時強制實施。原因在于應用程序模型中通用 Windows 平臺 (UWP) 需要從最低最終設備如電話和物聯網 (IoT) 設備擴展到功能最強大的臺式計算機和 Xbox 尤其重要。
對于復雜的應用程序,現代應用程序模型可能看上去限制性剛開始,但正如本文將介紹,有幾種方法的應用程序可以展開框并運行 (完成的任務和傳遞通知),甚至當不在前景中。
## 應用程序生命周期
在傳統 Win32 和.NET 桌面開發中,應用程序通常是在兩種狀態之一:"正在運行"或"未運行"和大多數情況下它們正在運行。這似乎很明顯,但思考的即時消息等 Skype 應用程序或類似 Spotify 的音樂應用: 用戶啟動它、 執行某些操作 (發送消息或搜索音樂),則響起和執行其他操作。同時,Skype 位于在等待消息進入,后臺并且 Spotify 保持播放音樂。這與花費的大部分時間中的狀態不運行的現代應用 (例如 Windows 商店應用程序基于 UWP),完全不同。
Windows 應用程序都在三種狀態之一: 正在運行、 掛起或未運行,如中所示?圖 1。當用戶啟動 Windows 應用程序時,例如通過開始菜單上的磁貼上點擊應用程序被激活并進入運行狀態。只要用戶與應用程序進行交互時,它將保持處于運行狀態。如果用戶導航離開應用程序或將其降至最低,激發的掛起的事件。這是應用程序進行序列化時它已恢復或重新激活,如應用程序或部分填充擴展窗體數據的當前頁它可能需要的任何狀態的機會。當應用程序處于掛起狀態時,其進程和線程由 Windows 掛起,不能執行。當用戶導航回該應用程序時,應用程序線程會被解凍和應用程序恢復運行狀態。
?
圖 1 Windows 應用程序生命周期
如果應用程序處于掛起的狀態,但是它使用 (通常是內存) 的資源,則需要用作其他用途,如運行另一個應用程序,該應用程序移到未運行狀態。
從應用程序執行的角度看,掛起和未運行狀態之間的區別是是否允許該應用程序駐留在內存中。當只是掛起應用程序時,它的執行被凍結,但所有其狀態信息保留在內存中。當應用程序未運行時,它從內存中刪除。當從移動應用程序掛起到未在運行時,會不觸發任何事件,因為很重要的應用程序進行序列化所有它從內存中,所需的狀態信息以防未在運行從重新激活它。
圖 2?顯示發生的資源使用情況與應用程序生命周期的轉換。應用程序激活時,它開始占用內存,通常達到相對穩定比爾。當掛起應用程序時,其內存使用量通常出現故障 — 緩沖區和使用的資源的發行,和 CPU 占用率變為零 (由操作系統強制執行)。當在移動應用程序從掛起到未運行時,內存和 CPU 的使用將轉到零,再次由操作系統強制執行。
?
圖 2 應用程序生命周期和資源使用情況
大量的 RAM 和大型頁文件的許多桌面系統上它并不常用 — 但不是不可能 — 從內存中,但這種轉換中刪除的應用程序是在移動設備和其他資源受限的設備上更常見。為此,務必測試 UWP 應用程序在各種設備上。Windows 仿真程序附帶使用 Visual Studio 會非常有用對于這一點 ;它允許開發人員能夠與目標設備作為小 512 MB 的內存。
## 擴展的執行
我所述的應用程序生命周期是有效 — 如果它們不會使用,應用程序不占用資源 — 但它會導致哪些應用程序需求不能完成其中的方案。例如,社會或通信的應用程序的一個典型用例是登錄并同步一組云數據 (聯系人、 源、 對話歷史記錄和等)。與基本應用程序生命周期所述,若要下載聯系人、 用戶需要保持該應用程序打開和在前臺中的全部時間 ! 另一個示例可能是導航或適用性的應用程序需要跟蹤用戶的位置。只要用戶切換到不同的應用程序或將設備置于其 pocket 時,這將不再起作用。需要有一種機制以允許應用程序運行較長時間。
通用 Windows 平臺引入了擴展的執行來幫助進行這些類型的情況的概念。有兩種情況下可以使用擴展的執行的位置:
1. 在應用程序處于運行狀態時的正則前臺執行期間的任何時刻。
2. 該應用程序接收到掛起的事件后 (是操作系統以將該應用程序移到掛起狀態) 在應用程序的掛起事件處理程序。
這兩種情況的代碼是相同的但應用程序的行為有點以不同的方式在每個。在第一種情況下,應用程序處于運行狀態,即使發生 (例如導航離開應用程序的用戶) 的程序通常會觸發掛起的事件。執行擴展在生效時,應用程序將永遠不會收到掛起事件。當釋放該擴展插件時,該應用程序將再次變為適合掛起。
與第二個用例,如果應用程序轉換到掛起狀態,它將保留在掛起狀態的擴展的時間。該擴展插件到期后,應用程序將進入掛起的狀態無進一步通知。
圖 3?演示如何使用擴展的執行來擴展應用程序的 uspending 狀態。首先,新 ExtendedExecutionSession 創建并附帶的原因和說明。這兩個屬性用于分配正確的資源設置為該應用程序 (即量的內存、 CPU 和允許它的執行時間) 以及公開有關應用程序在后臺執行的操作信息提供給用戶。然后,應用程序掛接如果稱為 Windows 不再可以支持擴展,例如,如果另一個高優先級的任務如前臺應用程序或傳入的 VoIP 呼叫,需要資源一個吊銷事件處理程序。最后,應用程序請求該擴展插件,并且如果成功,將從開始保存操作。如果拒絕該擴展插件,該應用程序將在執行掛起操作尚未收到的擴展功能,像常規的掛起事件。
圖 3 擴展 OnSuspending 處理程序中的執行
~~~
private async void OnSuspending(object sender, SuspendingEventArgs e)
{
? var deferral = e.SuspendingOperation.GetDeferral();
? using (var session = new ExtendedExecutionSession())
? {
??? session.Reason = ExtendedExecutionReason.SavingData;
??? session.Description = "Upload Data";
??? session.Revoked += session_Revoked;
??? var result = await session.RequestExtensionAsync();
??? if (result == ExtendedExecutionResult.Denied)
??? {
????? UploadBasicData();
??? }
??? // Upload Data
??? var completionTime = await UploadDataAsync(session);
? }
? deferral.Complete();
}
~~~
圖 4?顯示這對應用程序生命周期的影響 ; 將對其進行比較?圖 2。當應用程序獲取掛起事件時,它開始釋放或序列化的資源。如果應用程序確定它需要更多時間,并采用一個擴展,它將一直處于掛起狀態撤消該擴展插件。

圖 4 在擴展的執行過程的資源使用情況
情況 2 中前面所述,執行擴展無需請求僅在掛起的處理程序 ;它可以在任何時刻在應用程序處于運行狀態時請求。這可用于當在應用程序知道事先它將需要與前面所述導航布局應用程序可以繼續在后臺運行。代碼非常類似于前面的示例和中所示?圖 5。
圖 5 擴展在正則執行過程的執行
~~~
private async void StartTbTNavigationSession()
{
? using (var session = new ExtendedExecutionSession())
? {
??? session.Reason = ExtendedExecutionReason.LocationTracking;
??? session.Description = "Turn By Turn Navigation";
??? session.Revoked += session_Revoked;
??? var result = await session.RequestExtensionAsync();
??? if (result == ExtendedExecutionResult.Denied
??? {
????? ShowUserWarning("Background location tracking not available");
??? }
??? // Do Navigation
??? var completionTime = await DoNavigationSessionAsync(session);
? }
}
~~~
圖 6?顯示了這種情況下的應用程序生命周期。同樣,它也是非常相似。不同之處在于時執行擴展被吊銷,, 應用程序將可能迅速轉變通過掛起狀態進入未運行狀態。這是因為在這種情況下,僅由于資源不足,僅通過釋放資源可以緩解 (即,從內存中刪除該應用程序) 的情況通常撤消該擴展插件。

圖 6 在擴展的執行過程的資源使用情況
## 后臺任務
沒有應用程序可以在后臺中運行的另一種方法,這就是作為后臺任務。后臺任務是在應用程序中單獨實現 IBackgroundTask 接口的組件。這些組件可以沒有重量級 UI 框架的情況下執行并 (盡管它們也可以運行進程內與主應用程序可執行文件) 通常執行的單獨進程中。
激發相關聯的觸發器時執行后臺任務。觸發器是系統事件可以激發并激活應用程序,即使應用程序未運行。例如,可以使用特定時間間隔內 (說,每隔 30 分鐘) 生成 TimeTrigger、 應用程序的后臺任務將在這種情況下激活時激發該觸發器每隔 30 分鐘。有許多支持的 Windows,包括這些背景觸發器類型的觸發器類型: TimeTrigger、 PushNotificationTrigger、 LocationTrigger、 ContactStoreNotificationTrigger、 BluetoothLEAdvertisementWatcherTrigger、 UserPresent、 InternetAvailable 和 PowerStateChange。
使用后臺任務是一個三步驟過程: 該組件需要創建,然后在應用程序清單中聲明并隨后在運行時進行了注冊。
通常在單獨的 Windows 運行時 (WinRT) 組件項目中與 UI 項目相同的解決方案中實現后臺任務。這允許在一個單獨的進程,減少開銷由組件所需的內存中激活的后臺任務。所示的簡單實現 IBackgroundTask圖 7。IBackgroundTask 是一個簡單的界面,用于定義只是一種方法運行。這是在后臺任務觸發器被觸發時調用的方法。方法的唯一參數是一個包含有關激活 (例如,使用 toast 通知的操作相關聯的推送通知的負載) 和事件處理程序來處理取消等的生命周期事件的上下文的 IBackgroundTaskInstance 對象。當 Run 方法完成后時,將終止的后臺任務。為此,就像前面顯示的掛起處理程序中一樣是一定要使用的延遲對象 (還關閉 IBackgroundTaskInstance 懸掛) 如果您的代碼是異步的。
圖 7 BackgroundTask 實現
~~~
public sealed class TimerTask : IBackgroundTask
{
? public void Run(IBackgroundTaskInstance taskInstance)
? {
??? var deferral = taskInstance.GetDeferral();
??? taskInstance.Canceled += TaskInstance_Canceled;
??? await ShowToastAsync("Hello from Background Task");
??? deferral.Complete();
? }
? private void TaskInstance_Canceled(IBackgroundTaskInstance sender,
??? BackgroundTaskCancellationReason reason)
? {
??? // Handle cancellation
??? deferral.Complete();
? }
}
~~~
在應用程序清單中,還必須注冊的后臺任務。此注冊指示 Windows,但是觸發器類型、 入口點和可執行該任務的主機,如下所示:
~~~
<Extensions>
? <Extension Category="windows.backgroundTasks" EntryPoint="BackgroundTasks.TimerTask">
??? <BackgroundTasks>
????? <Task Type="timer" />
??? </BackgroundTasks>
? </Extension>
~~~
這也可以不深入探討 XML 通過使用 Visual Studio 附帶在清單設計器的情況下完成。
最后,還必須在運行時,注冊該任務并顯示了?圖 8。此處我使用 BackgroundTaskBuilder 對象來注冊該任務將激發每隔 30 分鐘 TimeTrigger Internet 是否可用。這是觸發器的理想的為諸如更新磁貼或定期同步少量數據之類的常見操作類型。
圖 8 后臺任務注冊
~~~
private void RegisterBackgroundTasks()
{
? BackgroundTaskBuilder builder = new BackgroundTaskBuilder();
? builder.Name = "Background Test Class";
? builder.TaskEntryPoint = "BackgroundTaskLibrary.TestClass";
? IBackgroundTrigger trigger = new TimeTrigger(30, true);
? builder.SetTrigger(trigger);
? IBackgroundCondition condition =
??? new SystemCondition(SystemConditionType.InternetAvailable);
? builder.AddCondition(condition);
? IBackgroundTaskRegistration task = builder.Register();
? task.Progress += new BackgroundTaskProgressEventHandler(task_Progress);
? task.Completed += new BackgroundTaskCompletedEventHandler(task_Completed);
}
~~~
后臺任務的最大優勢也可以是其大麻煩: 由于在后臺 (在用戶可能需要執行一些重要在前臺或該設備處于待機狀態時) 運行后臺任務,它們是嚴格的限制內存和他們可以使用的 CPU 時間量。例如,后臺任務注冊中?圖 8?將僅為 30 秒對運行和不能使用超過 16 MB 的內存在設備上有 512 MB 內存 ; 內存上限進行縮放,在設備上的內存量。在開發和實現后臺任務時, 務必考慮到這一點。后臺任務應進行測試的各種設備,尤其是低端設備、 之前發布的應用程序。有幾個要同時請注意其他事項:
* 如果 Battery Saver 是可用并處于活動狀態 (通常當電池是低于費用閾值),后臺任務不能運行,直到電池過去的電池電量節省閾值重新充電。
* 在以前版本的 Windows 中,將"固定"到鎖之前他們之所以能夠執行在后臺,且在某些情況下,所需的應用程序沒有可能是已注冊的設備級的后臺任務的最大數量。這不再是這種情況在 Windows 10,但應用程序必須始終調用 BackgroundExecutionManger.RequestAcessAsync 來聲明其意圖在后臺中運行。
## 不要聯系同步的更好方式
有許多后臺操作可完成與任一擴展執行或通過后臺任務。通常,是更好的做法盡可能使用后臺任務 — — 它們更可靠、 更高效。
例如,上文所述的方案 — 應用程序首次啟動時同步數據 — 還可以進行,并且更高效地通過后臺任務,在這種情況下使用觸發器不熟悉的 Windows 10: 應用程序觸發器。
(如 DeviceUseTrigger) ApplicationTrigger 屬于一種特殊的類的直接從應用程序的前景部分觸發的觸發器。這是通過顯式調用 RequestAsync 觸發器對象上。ApplicationTrigger 是對于應用程序要在應才有機會在后臺繼續進行如果該應用程序不再位于前臺,而該操作不依賴于緊密耦合的前景前臺啟動操作的情況下特別有用。下面演示舉例說明如何可以代替大多數情況下擴展執行 ApplicationTrigger 任務:
~~~
var appTrigger = new ApplicationTrigger();
var backgroundTaskBuilder = new BackgroundTaskBuilder();
backgroundTaskBuilder.Name = "App Task";
backgroundTaskBuilder.TaskEntryPoint = typeof(AppTask).FullName;
backgroundTaskBuilder.SetTrigger(appTrigger);
backgroundTaskBuilder.Register();
var result = await appTrigger.RequestAsync();
~~~
## 總結
本文提供 Windows 10 中的應用程序生命周期和后臺執行的概述,并引入了幾個新的應用程序可用于在后臺運行的機制: 擴展執行和后臺任務。后臺任務是更好的選擇為低端和內存約束設備 (如電話),而擴展的執行是更適用于更高端設備 (如桌面 Pc)。
* * *
Shawn Henry?*是通用的 Windows 平臺構建團隊的高級項目經理。與他聯系在 Twitter 上關注:[@shawnhenry](https://twitter.com/@shawnhenry)。*
- 介紹
- Microsoft .NET - .NET 和通用 Windows 平臺開發
- 圖形和動畫 - Windows 組合支持 10 倍縮放
- 應用生命周期 - 通過后臺任務和擴展執行使應用處于活動狀態
- 通知 - Windows 10 中的自適應和交互式通知
- 應用集成 - 在 Windows 10 上鏈接和集成應用
- Visual Studio 工具 - NuGet 功能增強了 Windows 10 的開發功能
- UI 設計 - 通用 Windows 應用的響應式設計
- UI 設計 - 適用于 Windows 10 的自適應應用
- 數字墨跡 - Windows 10 中的墨跡交互
- 游戲開發 - 使用 Unity 為通用 Windows 平臺編寫游戲
- 結束語 - 歡迎使用 Windows 10 應用開發
- 編者寄語 - 從 3.0 開始的發展之路