Háttérfeladatok használata Windows alkalmazásokban

Megjegyzés:

Ez a cikk a Windows-futtatókörnyezet (WinRT) BackgroundTaskBuilder API-val készült háttérfeladatokat ismerteti a Windows. ApplicationModel.Background névtér csomagidentitású alkalmazásokhoz, beleértve az UWP-t és a csomagolt asztali alkalmazásokat. Ha új alkalmazást hoz létre, vagy meglévő alkalmazást migrál Windows App SDK, tekintse meg a Az Windows alkalmazások háttérfeladatainak használata és Háttéri feladatmigrálási stratégia.

Megtudhatja, hogyan hozhat létre és regisztrálhat háttérfeladatot az alkalmazásban a Windows-futtatókörnyezet (WinRT) BackgroundTaskBuilder osztályban.

Háttérfeladat regisztrálása

Az BackgroundTask mintában talál egy teljes példát egy háttérfeladat Univerzális Windows-platform (UWP)-alkalmazásokban való regisztrálására.

Az alábbi példa egy 15 perces ismétlődő időzítőn futó Win32 COM-feladat regisztrációját mutatja be.

Háttérfeladat regisztrálásához először létre kell hoznia a BackgroundTaskBuilder osztály új példányát . Az BackgroundTaskBuilder osztály háttérfeladatokat hoz létre és regisztrál az alkalmazásban. Az alábbi példakód bemutatja, hogyan hozható létre az osztály új példánya BackgroundTaskBuilder :

using System;
using Windows.ApplicationModel.Background;

public IBackgroundTaskRegistration RegisterBackgroundTaskWithSystem(IBackgroundTrigger trigger, Guid entryPointClsid, string taskName)
{
    BackgroundTaskBuilder builder = new BackgroundTaskBuilder();

    builder.SetTrigger(trigger);
    builder.SetTaskEntryPointClsid(entryPointClsid);

    BackgroundTaskRegistration registration;
    if (builder.Validate())
    {
        registration = builder.Register(taskName);
    }
    else
    {
        registration = null;
    }

    return registration;
}

RegisterBackgroundTaskWithSystem(new TimeTrigger(15, false), typeof(TimeTriggeredTask).GUID, typeof(TimeTriggeredTask).Name);

A RegisterBackgroundTaskWithSystem metódus három paramétert használ:

  • trigger: Az eseményindító, amely elindítja a háttérfeladatot.
  • entryPointClsid: A háttérfeladat belépési pontjának osztályazonosítója.
  • taskName: A háttérfeladat neve.

A RegisterBackgroundTaskWithSystem metódus létrehozza az BackgroundTaskBuilder osztály új példányát, és beállítja a háttérfeladat eseményindító- és belépésipont-osztályazonosítóját. A metódus ezután regisztrálja a háttérfeladatot a rendszeren.

Megjegyzés:

Ez az osztály nem agilis, ami azt jelenti, hogy figyelembe kell vennie a szálmodellt és a csomagolás viselkedését. További információ: Threading and Marshaling (C++/CX) és Az Windows-futtatókörnyezet objektumok használata többszálú környezetben (.NET).

Modern készenléti állapot kezelése háttérfeladatban

A BackgroundTaskBuilder és a kapcsolódó API-k már lehetővé teszik a csomagolt asztali alkalmazások számára a háttérfeladatok futtatását. Az API mostantól kibővíti ezeket az API-kat, hogy lehetővé tegye ezeknek az alkalmazásoknak a kód modern készenléti állapotban való végrehajtását. A frissítés olyan tulajdonságokat is hozzáad, amelyeket egy alkalmazás lekérdezhet annak megállapításához, hogy a rendszer szabályozni fogja-e az alkalmazás háttérfeladatait a modern készenléti állapotban az akkumulátor üzemidejének megőrzése érdekében. Ez olyan forgatókönyveket tesz lehetővé, mint a VoIP-hívásokat fogadó alkalmazások vagy a modern készenléti állapotból érkező leküldéses értesítések.

Megjegyzés:

Ebben a szakaszban a "csomagolt asztali alkalmazások" olyan Win32-alkalmazásokra utalnak, amelyek csomagidentitással rendelkeznek (például Asztali híd vagy Ritkán aláírt csomagolt alkalmazások), és belépési pontként fő (vagy wmain) függvényt használnak.

Az alábbi példa bemutatja, hogy egy alkalmazásfejlesztő hogyan használhatja a BackgroundTaskBuilder API-t, hogy legfeljebb egy feladatot regisztráljon a megadott tevékenységnévvel. A minta azt is bemutatja, hogyan ellenőrizheti és engedélyezheti a feladatregisztrációt, hogy modern készenléti állapotban fusson az alkalmazás legkritikusabb feladataihoz.

// The following namespace is required for BackgroundTaskBuilder APIs. 
using Windows.ApplicationModel.Background; 

// The following namespace is required for API version checks. 
using Windows.Foundation.Metadata; 

// The following namespace is used for showing Toast Notifications. This 
// namespace requires the Microsoft.Toolkit.Uwp.Notifications NuGet package 
// version 7.0 or greater. 
using Microsoft.Toolkit.Uwp.Notifications; 

// Incoming calls are considered to be critical tasks to the operation of the app. 
const string IncomingCallTaskName = "IncomingCallTask"; 
const string NotificationTaskName = "NotificationTask"; 
const string PrefetchTaskName = "PrefetchTask"; 

public static bool IsAllowedInBackground(BackgroundAccessStatus status) { 
    return ((status != BackgroundAccessStatus.Denied) && 
            (status != BackgroundAccessStatus.DeniedBySystemPolicy) && 
            (status != BackgroundAccessStatus.DeniedByUser) && 
            (status != BackgroundAccessStatus.Unspecified)); 
} 

public async void RegisterTask(IBackgroundTrigger trigger, 
                               Guid entryPointClsid, 
                               string taskName, 
                               bool isRunInStandbyRequested) 
{ 
    var taskBuilder = new BackgroundTaskBuilder(); 
    taskBuilder.SetTrigger(trigger); 
    taskBuilder.SetTaskEntryPointClsid(entryPointClsid); 

    // Only the most critical background work should be allowed to proceed in 
    // modern standby. Additionally, some platforms may not support modern 
    // or running background tasks in modern standby at all. Only attempt to 
    // request modern standby execution if both are true. Requesting network 
    // is necessary when running in modern standby to handle push notifications. 
    if (IsRunInStandbyRequested && taskBuilder.IsRunningTaskInStandbySupported) 
    { 
        var accessStatus = BackgroundExecutionManager.GetAccessStatusForModernStandby(); 
        if (!IsAllowedInBackground(accessStatus) 
        { 
            await BackgroundExecutionManager.RequestAccessKindForModernStandby( 
                    BackgroundAccessRequestKind.AllowedSubjectToSystemPolicy, 
                    "This app wants to receive incoming notifications while your device is asleep"); 
        } 

        accessStatus = BackgroundExecutionManager.GetAccessStatusForModernStandby(); 

        if (IsAllowedInBackground(accessStatus) 
        { 
            taskBuilder.IsRunningTaskInStandbyRequested = true; 
            taskBuilder.IsNetworkRequested = true; 
        } 
    } 

    // Check that the registration is valid before attempting to register. 
    if (taskBuilder.IsRegistrationValid) 
    { 
        // If a task with the specified name already exists, it is unregistered 
        // before a new one is registered. Note this API may still fail from 
        // catastrophic failure (e.g., memory allocation failure). 
        taskBuilder.Register(taskName); 
    } 

    return; 
} 

RegisterTask(new PushNotificationTrigger(), "{INSERT-YOUR-GUID-HERE}", IncomingCallTaskName, true); 

Ellenőrizze, hogy a háttérfeladatok túllépték-e a ráfordítási keretüket a modern készenléti állapotban

Az alábbi mintakód bemutatja, hogy az alkalmazásfejlesztők hogyan használhatják a BackgroundWorkCost.WasApplicationThrottledInStandby és a BackgroundWorkCost.ApplicationEnergyUseLevel parancsot, hogy monitorozzák és reagáljanak arra, hogy háttérfeladataik kimerítsék az alkalmazás költségvetését. Az alkalmazásfejlesztő úgy reagálhat, hogy csökkenti a modern készenléti állapotban végzett alacsonyabb prioritású munkát. Vegye figyelembe, hogy ez az előző minta kódjára támaszkodik.

public async void ReduceBackgroundCost() 
{ 
    BackgroundTaskRegistration callTask; 
    BackgroundTaskRegistration notificationTask; 
    BackgroundTaskRegistration prefetchTask; 

    // Nothing to do if the app was not or will not be throttled. 
    if (!BackgroundWorkCost.WasApplicationThrottledInStandby && 
        (BackgroundWorkCost.ApplicationEnergyUseLevel != StandbyEnergyUseLevel.OverBudget)) 
    { 
        return; 
    } 

    foreach (var task in BackgroundTaskRegistration.AllTasks) 
    { 
        switch (task.Value.Name) { 
        case IncomingCallTaskName: 
            callTask = task.Value; 
            break; 

        case NotificationTaskName: 
            notificationTask = task.Value; 
            break; 

        case PrefetchTaskName: 
            prefetchTask = task.Value; 
            break; 

        default: 
        } 
    } 

    if (callTask.WasTaskThrottledInStandby) 
    { 
        // Unset the throttle flag after acknowledging it so the app can 
        // react to the same task being throttled again in the future. 
        task.Value.WasTaskThrottledInStandby = false; 

        // Notify the user that the notification was missed. 
        new ToastContentBuilder() 
            .AddText("You missed a call") 
            .AddText(task.Value.Name) 
            .Show(); 

        // Because the incoming calls were not activated, demote less notifications 
        // tasks so the calls can be delivered promptly in the future. 
        RegisterTask(notificationTask.Value.Trigger, 
                     typeof(TimeTriggeredTask).GUID, 
                     notificationTask.Value.Name, 
                     false); 
    } 

    // Note that if incoming call tasks were throttled in some previous modern 
    // standby session, the application energy use was over budget for some period. 
    // Demote unimportant tasks like prefetch work to avoid calls and notifications 
    // from being throttled.
    if (callTask.WasTaskThrottledInStandby) ||
        (BackgroundWorkCost.ApplicationEnergyUseLevel == StandbyEnergyUseLevel.OverBudget))
    {
        RegisterTask(prefetchTask.Value.Trigger,
                     typeof(TimeTriggeredTask).GUID,
                     prefetchTask.Value.Name,
                     false);
    }

    return;
}

Az alábbiakban a C++WinRT/C# mintakód incrementális végponttól végpontig történő frissítése található a GitHub-on.

A példa bemutatja, hogyan használhatja a BackgroundWorkCost.ApplicationEnergyUseTrendet annak figyelésére, hogy a háttérfeladatok hogyan trendelnek a költségvetésük kimerülése felé. Azt is megakadályozhatja, hogy a legdrágább háttérfeladatok modern készenléti állapotban fussanak, és megakadályozza, hogy a háttérfeladatok modern készenléti állapotban fussanak, ha az alkalmazás túl gyorsan használja a költségvetését. Ez a minta a korábbi minták kódjára támaszkodik.

public async void ReduceBackgroundCostPreemptively() 
{ 
    BackgroundTaskRegistration mostExpensiveTask = null; 

    // We can't do anything preemptively since the trend isn't known. 
    if (!BackgroundWorkCost.IsApplicationEnergyUseTrendKnown) 
    { 
        return; 
    } 

    // The app is not trending towards being over budget, so this method can 
    // return early. 
    if ((BackgroundWorkCost.ApplicationEnergyUseTrend != EnergyUseTrend.OverBudget) && 
        (BackgroundWorkCost.ApplicationEnergyUseTrend != EnergyUseTrend.OverHalf)) 
    { 
        return; 
    } 

    // The application is going exceeding its budget very quickly. Demote the 
    // most expensive task that is not the call task before call tasks start being 
    // throttled. 
    if (BackgroundWorkCost.ApplicationEnergyUseTrend == EnergyUseTrend.OverBudget) 
    { 
        foreach (var task in BackgroundTaskRegistration.AllTasks) 
        { 
            if ((task.Value.Name != IncomingCallTaskName) && 
                ((mostExpensiveTask == null) || 
                 (mostExpensiveTask.ApplicationEnergyUseTrendContributionPercentage < 
                  task.Value.ApplicationEnergyUseTrendContributionPercentage))) 
            { 
                mostExpensiveTask = task.Value; 
            } 
        } 
    } 

    if (mostExpensiveTask != null) 
    { 
        RegisterTask(mostExpensiveTask.Trigger, 
                     typeof(TimeTriggeredTask).GUID, 
                     mostExpensiveTask.Name, 
                     false); 
    } 

    // The application is trending toward eventually exceeding its budget. Demote the 
    // least important prefetch task before calls and notifications are throttled. 
    foreach (var task in BackgroundTaskRegistration.AllTasks) 
    { 
        if (task.Value.Name == PrefetchTaskName) { 
            RegisterTask(task.Value.Trigger, 
                         typeof(TimeTriggeredTask).GUID, 
                         task.Value.Name, 
                         false); 
        } 
    } 

    return; 
} 

Háttérfeladatok és hálózati kapcsolat

Ha a háttérfeladat hálózati kapcsolatot igényel, vegye figyelembe az alábbi szempontokat.

  • A SocketActivityTrigger használatával aktiválhatja a háttérfeladatot egy csomag érkezésekor, és rövid élettartamú feladatot kell végrehajtania. A feladat végrehajtása után a háttérfeladatnak le kell fejeződnie, hogy energiát takarítson meg.
  • A ControlChannelTriggerrel aktiválhatja a háttérfeladatot egy csomag érkezésekor, és hosszú élettartamú feladatot kell végrehajtania.
  • Adja hozzá az InternetAvailable feltételt (BackgroundTaskBuilder.AddCondition) a háttérfeladathoz, hogy késleltetve aktiválja a háttérfeladatot, amíg a hálózati verem nem fut. Ez a feltétel energiát takarít meg, mert a háttérfeladat nem lesz végrehajtva, amíg el nem érhető a hálózati hozzáférés. Ez a feltétel nem biztosít valós idejű aktiválást.
  • A használt eseményindítótól függetlenül állítsa be az IsNetworkRequested parancsot a háttérfeladatra, hogy a hálózat a háttérfeladat futtatása közben is megmaradjon. Ez azt jelzi a háttérfeladat-infrastruktúrának, hogy a feladat végrehajtása közben is tartsa fenn a hálózatot, még akkor is, ha az eszköz csatlakoztatott készenléti üzemmódba lépett. Ha a háttérfeladat nem használja az IsNetworkRequested szolgáltatást, akkor a háttérfeladat nem fogja tudni elérni a hálózatot csatlakoztatott készenléti módban.