1. 程式人生 > >UWP -- Background Task 深入解析

UWP -- Background Task 深入解析

filename 異步 must spa 取消 處理 net ndb 文件

原文:UWP -- Background Task 深入解析

1. 重點

鎖屏問題

從 Windows 10 開始,用戶無須再將你的應用添加到鎖屏界面,即可利用後臺任務,通用 Windows 應用必須在註冊任何後臺觸發器類型之前調用 RequestAccessAsync:

await BackgroundExecutionManager.RequestAccessAsync();

資源限制

由於對於內存較低的設備的資源約束,後臺任務可能具有內存限制,該限制決定了後臺任務可以使用的內存上限

在內存受限的設備上,對於可以安裝在一臺設備上並在任何給定時間使用後臺任務的應用數量有所限制。 如果超出該數量,將無法調用註冊所有後臺任務時所需的 RequestAccessAsync

如果後臺任務嘗試執行超過此限制的操作,則該操作將失敗,並可能生成內存不足的異常情況,但該任務可以處理此情況如果該任務無法處理內存不足的異常情況,或者由於嘗試的操作的性質導致無法生成內存不足的異常情況,任務將立即終止

你可以使用 MemoryManager PAI 查詢當前內存使用量和限制,以發現上限(若有),並監視正在進行的後臺任務內存使用量

進程內後臺任務 entry-point

對於進程內後臺活動,不要設置 TaskEntryPoint.。將其保留為空可啟用默認入口點,這是 Application 對象上稱為 OnBackgroundActivated() 的一種新的受保護方法

節電模式

除非你豁免你的應用,以便它可以在節電模式打開時仍可以運行後臺任務和接收推送通知,否則當節電模式功能啟用時,如果設備未連接到外部電源且電量低於指定剩余電量,它將阻止後臺任務運行。 這不會阻止你註冊後臺任務

時間限制

後臺任務受其基於觸發器類型獲取的時鐘時間使用的限制

大多數觸發器限制為 30 秒的時鐘時間使用,如果後臺活動的運行時間超過執行時間限制,即使在應用的前臺進程內運行,後臺活動也會終止(進程內後臺任務)。而另一些觸發器在完成耗時任務時最多可以運行 10 分鐘。 為了延長電池使用時間並為前臺應用提供最佳用戶體驗,後臺任務應該是輕量級任務

2. 概述

Reason: Windows Store apps have their threads suspended when not in the forground.
Benefit: This prevents background apps fom consuming battery power and prevents apps the user is not interacting with from affecting the responsiveness of the foreground app.

  • System can update your tile or show a toast notification even when your app is suspended or terminated. —- Toast and Notification

  • Your app could transfer large files even when in the background. — Networking

All using background task. Windows Store apps can execute code when not in the foreground by using background task.

Background Task architecture

  1. Implement the code you want executed as a background task.

  2. Decide what triggers your background task code (eg: timer , user log in , ..)

  3. Add a manifest declaration so that Windows knows how to active background task code.
    只是決定什麽情況下觸發,從而運行

  4. Register your app’s background tasks with Windows the first time your app is activated.

註意:
第一次需要在代碼中註冊
此外,需要在項目中添加對 WinRT 的引用,reference

Background task 啟動過程

When a trigger occurs, Windows creates a new process, loads your background task code into it, and calls an entry point. The background task process runs in the package’s app container. (background task typically execute in a different process than the app’s process)

註:Windows Store apps runs in a different security context than a desktop apps. The security context is called app container, and it restricts which resources a Windows Store app can access.

a new process —- 獨立進程 (backgroundtaskhost.exe)

需要說明,一般background task 運行在哪個進程,由manifest – declarations – background task – Executable 決定,文檔上:

For most of the triggers, you must leave this blank, Which tells Windows to use its own BackgroundTaskHost.exe process.(系統的BackgroundTaskHost.exe, 任務管理器只看見一個)

Background is not allowed to update the app’s user interface, but can update tiles and badges, or cause the display of a toast notification

重點:

The background task process runs in the package’s app container. This means that the manifest’s package capabilities and app declarations do apply to the background task process. The background task process can write to the package’s data setting and folders. (for an app and its background tasks to communicate with each other). One process can signal when data is ready by calling ApplicationData’s SingalDataChanged method.

Your app must run at least once in order to register a background task and its desired trigger with Windows.(第一次在代碼中註冊)

Once registered, your app can be running, suspended, or even terminated. When the trigger occurs, Windows starts your app’s background task.

//在註冊前運行即可
await Windows.ApplicationModel.Background.BackgroundExecutionManager.RequestAccessAsync();

Background task is the only way to execute code when a PC is in Connected Standby mode.

3. 使用後臺任務支持應用

3.1 在後臺播放媒體

3.2 進程內後臺任務和進程外後臺任務

有兩種方法可以實現後臺任務:

  • 進程內
    • 應用及其後臺進程在同一進程中運行;
  • 進程外
    • 應用及其後臺進程分別在單獨的進程中運行。 進程內後臺支持在 Windows 10 版本 1607 中引入,目的是簡化編寫後臺任務。 但仍可以編寫進程外後臺任務

進程外後臺任務實現為操作系統在獨立進程 (backgroundtaskhost.exe) 中運行的輕型類。 進程外後臺任務編寫來實現 IBackgroundTask 接口的類。 通過使用 BackgroundTaskBuilder 類註冊後臺任務。 註冊後臺任務時,類名稱將用於指定入口點

4. 後臺任務指南

內外進程中的任務

技術分享

CPU 配額

後臺任務受其基於觸發器類型獲取的時鐘時間使用的限制。 大多數觸發器限制為 30 秒的時鐘時間使用,而另一些觸發器在完成耗時任務時最多可以運行 10 分鐘。 為了延長電池使用時間並為前臺應用提供最佳用戶體驗,後臺任務應該是輕量級任務。

使用 BackgroundTaskDeferral

如果後臺任務類運行異步代碼,則確保使用延遲。 否則,當使用 Run 方法(或針對進程內後臺任務使用 OnBackgroundActivated 方法)時,你的後臺任務可能會提前終止

BackgroundTaskDeferral _deferral; // Note: defined at class scope so we can mark it complete inside the OnCancel() callback if we choose to support cancellation
    public async void Run(IBackgroundTaskInstance taskInstance)
    {
        _deferral = taskInstance.GetDeferral()
        //
        // TODO: Insert code to start one or more asynchronous methods using the
        //       await keyword, for example:
        //
        // await ExampleMethodAsync();
        //

        _deferral.Complete();
    }

準備應用更新

如果你的應用將更新,請創建和註冊一個 ServicingComplete 後臺任務,以便取消註冊適用於前一版本應用的後臺任務,並註冊適用於新版本應用的後臺任務。 此時也非常適合在前臺運行的上下文之外執行所需的應用更新

建議每個 app 都可以裝一個,它可以在 你沒運行之前做一些操作

5. 1.Implement your Background Task’s code

 namespace MyApp.BackgroundTasks
    { // NOTE: determines filename "MyApp.BackgroundTasks.WinMD"    
        using Windows.ApplicationModel.Background;  // For IBackgroundTask & IBackgroundTaskInstance 
        using Windows.Storage;

        // NOTE: WinRT components MUST be public and sealed    
        public sealed class MyBackgroundTask : IBackgroundTask
        {
            public void Run(IBackgroundTaskInstance taskInstance)
            {          // Register cancelation handler (see the "Background task cancellation" section)          
                       // NOTE: Once canceled, a task has 5 seconds to complete or the process is killed          
                taskInstance.Canceled +=              (IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) => 
                {             
                    // TODO: Tell task it should cancel itself as soon as possible...          
                };

                // Recommended: Adjust task behavior based on CPU and network availability          
                // For example: A mail app could download mail for all folders when cost is          
                // low and only download mail for the Inbox folder when cost is high          
                switch (BackgroundWorkCost.CurrentBackgroundWorkCost)
                {
                    case BackgroundWorkCostValue.Low:       // The task can use CPU & network             
                    case BackgroundWorkCostValue.Medium:    // The task can use some CPU & network             
                    case BackgroundWorkCostValue.High:      // The task should avoid using CPU & network                
                    // This example records the last trigger time in an application data setting                
                    // so the app can read it later if it chooses. We do regardless of work cost.                
                        ApplicationData.Current.LocalSettings.Values["LastTriggerTime"] =  DateTimeOffset.Now;
                        break;
                }
            }
        }
    }

Must implemented as a WinRT comment in VS. This project simply creates a dynamic-link library file. The file extension is .WinMD instead of .DLL .

When you register the full name of this class. The windows will be ready to execute this task ,it will try to load a .WinMD file whose name matches the namespace.

加載這文件時候,會先加載構造函數,不寫系統默認一個空構造,你寫了就不去加載這個空的構造函數。(包含run)

6. Decide what triggers your Background Task’s code

註冊要運行的後臺任務

通過在 BackgroundTaskRegistration.AllTasks 屬性中叠代,查明後臺任務是否已註冊。 此步驟非常重要;如果應用不檢查現有後臺任務註冊,則它可能會輕松多次註冊該任務,這會導致性能問題和工作結束前超出任務的最大可用 CPU 時間

    var taskRegistered = false;
    var exampleTaskName = "ExampleBackgroundTask";

    foreach (var task in BackgroundTaskRegistration.AllTasks)
    {
        if (task.Value.Name == exampleTaskName)
        {
            taskRegistered = true;
            break;
        }
    }

如果後臺任務尚未註冊,則使用 BackgroundTaskBuilder 創建你的後臺任務的一個實例。 任務入口點應為命名空間為前綴的後臺任務的名稱。

後臺任務觸發器控制後臺任務何時運行。 有關可能的觸發器的列表,請參閱 SystemTrigger。
例如,此代碼創建一個新後臺任務並將其設置為在 TimeZoneChanged 觸發器引發時運行:

var builder = new BackgroundTaskBuilder();

builder.Name = exampleTaskName;
builder.TaskEntryPoint = "RuntimeComponent1.ExampleBackgroundTask";
builder.SetTrigger(new SystemTrigger(SystemTriggerType.TimeZoneChange, false));

(可選)在觸發器事件發生後,你可以添加條件控制任務何時運行。 例如,如果你不希望在用戶存在前運行任務,請使用條件 UserPresent。 有關可能條件的列表,請參閱 SystemConditionType

builder.AddCondition(new SystemCondition(SystemConditionType.UserPresent));

通過在 BackgroundTaskBuilder 對象上調用 Register 方法來註冊後臺任務。 存儲 BackgroundTaskRegistration 結果,以便可以在下一步中使用該結果

BackgroundTaskRegistration task = builder.Register();

通用 Windows 應用必須在註冊任何後臺觸發器類型之前調用 RequestAccessAsync:

await BackgroundExecutionManager.RequestAccessAsync();

使用事件處理程序處理後臺任務完成

你應該使用 BackgroundTaskCompletedEventHandler 註冊一個方法,以便應用可以從後臺任務中獲取結果。 當啟動或恢復應用時,如果自從上次在應用前臺運行後後臺任務就已完成,將調用標記方法。 (如果應用當前位於前臺時後臺任務完成,將立即調用 OnCompleted 方法

private void OnCompleted(IBackgroundTaskRegistration task, BackgroundTaskCompletedEventArgs args)
    {
        var settings = Windows.Storage.ApplicationData.Current.LocalSettings;
        var key = task.TaskId.ToString();
        var message = settings.Values[key].ToString();
        UpdateUI(message);
    }

回到已註冊後臺任務的位置。 在該代碼行之後,添加一個新的 BackgroundTaskCompletedEventHandler 對象。 提供 OnCompleted 方法作為 BackgroundTaskCompletedEventHandler 構造函數的參數:

task.Completed += new BackgroundTaskCompletedEventHandler(OnCompleted);

在應用清單中聲明你的應用使用後臺任務

略^^

具體 Trigger 及其中區別

7. Add manifest declaration

The meaning of Executable field, this tells Windows which process to execute when the trigger fires. (!!!)

This process will load your WinRT component’s .WinMD file and execute your task’s code. There are two options for this field. For most of the triggers, you must leave this field blank, which tells Windows to use its own Background TaskHost.exe process. (Windows or App container?)

註釋:Windows Store apps run in a different security context than desktop apps. This security context is called an app container (discussed in the appendix, “App containers”), and it restricts which resources a Windows Store app can access.

For a PushNotificationTrigger, you can leave this field blank or you can specify(指定) the name of your own app’s executable. If you use the latter, Windows will have your app’s process load the WinRT component and run the task in the same process as your app.

This is not the recommended thing to do, but it allows your background task’s code the ability to access the same state (memory) as your app. However, if your app is suspended, all threads but the thread running the background task code remain suspended, so you must not perform any interthread communication or deadlocks will occur. In addition, because the GUI thread remains suspended, the background task cannot update the app’s user interface. If the app’s process is not running, Windows will activate it, but the app is not launched with a main view or hosted view activation. The result of all this is that your background task cannot have any expectations of the app’s state and, in fact, the app might not have its state fully initialized.

For a ControlChannelTrigger, you must not leave the Executable field blank; instead, you must specify your app’s executable name and your WinRT component’s .WinMD file must load in the app’s process.

As mentioned previously, the ControlChannelTrigger is used for RTC apps, and these apps typically have a socket open in the background task. For the app to respond to the incoming call on the socket, the background task and the app have to share the same process. Everything I said earlier still holds true in this scenario too; that is, the app will not be fully initialized and you should avoid interthread communication.

For the declaration’s Entry Point field, enter the full name (including the namespace) of the WinRT class you created in step 1 (for example, MyApp.BackgroundTasks.MyBackgroundTask). This tells the host process the name of the .WinMD file to load (MyApp.BackgroundTasks.WinMD) and the name of the class to construct in order to call its Run method.

Lock-Screen allowing that app’s background tasks to consume system resources even when the PC is on battery power. These apps typically have a real-time networking requirement like a chat or VoIP application

最多顯示七個,可以自己去系統裏面設置(你的app得支持lock-screen 才行)

8.

UWP -- Background Task 深入解析