Rimandare la sospensione dell'app con l'esecuzione estesa

Questo articolo illustra come usare l'esecuzione estesa per posticipare il momento in cui l'app viene sospesa in modo che possa essere eseguita mentre è ridotta a icona o sotto la schermata di blocco.

Quando l'utente riduce a icona o si allontana da un'app, questa viene messa in stato sospeso. La memoria viene mantenuta, ma il codice non viene eseguito. Questo vale per tutte le edizioni del sistema operativo con un'interfaccia utente visiva. Per maggiori dettagli su quando l'app è sospesa, vedere Ciclo di vita dell'applicazione.

In alcuni casi può essere necessario mantenere l'esecuzione di un'app, anziché essere sospesa, quando l'utente si allontana dall'app o mentre è ridotta a icona. Ad esempio, un'app di conteggio dei passaggi deve restare in esecuzione e tenere traccia dei passaggi anche quando l'utente si sposta per usare altre app.

Se un'app deve continuare a essere in esecuzione, il sistema operativo può mantenerla in esecuzione oppure può richiedere se continuare l'esecuzione. Ad esempio, quando si riproduce audio in background, il sistema operativo può mantenere un'app in esecuzione più a lungo se si seguono questi passaggi per Riproduzione multimediale in background. In caso contrario, è necessario richiedere manualmente più tempo. La quantità di tempo che si può ottenere per mantenere l'esecuzione in background può essere di alcuni minuti, ma è necessario essere pronti a gestire la sessione revocata in qualsiasi momento. Questi vincoli di tempo del ciclo di vita dell'applicazione sono disattivati mentre l'app è in esecuzione in un debugger. Per questo motivo è importante testare l'esecuzione estesa e altri strumenti per posticipare la sospensione dell'app mentre non è in esecuzione in un debugger o usando gli eventi del ciclo di vita disponibili in Visual Studio.

Creare una ExtendedExecutionSession per richiedere più tempo per completare un'operazione in background. Il tipo di ExtendedExecutionSession creato è determinato dall'oggetto ExtendedExecutionReason fornito al momento della creazione. Sono disponibili tre valori di enumerazione ExtendedExecutionReason : Unspecified, LocationTracking e SavingData. È possibile richiedere una sola sessione ÈxtendedExecutionSession per volta. Il tentativo di creare un'altra sessione mentre una richiesta di sessione approvata è attualmente attiva causa la generazione dell'eccezione 0x8007139F dal creatore di ExtendedExecutionSession che indica che il gruppo o la risorsa non è nello stato corretto per eseguire l'operazione richiesta. Non usare ExtendedExecutionForegroundSession e ExtendedExecutionForegroundReason in quanto richiedono funzionalità limitate e non sono disponibili per l'uso nelle applicazioni Store.

Esecuzione mentre è ridotta a icona

Esistono due casi in cui è possibile usare l'esecuzione estesa:

  • In qualsiasi momento durante l'esecuzione regolare in primo piano, mentre l'applicazione si trova in stato di esecuzione.
  • Dopo che l'applicazione ha ricevuto un evento di sospensione (il sistema operativo sta per spostare l'app nello stato sospeso) nel gestore eventi di sospensione dell'applicazione.

Il codice per questi due casi è lo stesso, ma l'applicazione si comporta in modo leggermente diverso in ciascun caso. Nel primo caso, l'applicazione rimane nello stato di esecuzione, anche se si verifica un evento che normalmente attiverebbe la sospensione , ad esempio l'utente che si allontana dall'applicazione. L'applicazione non riceverà mai un evento di sospensione mentre l'estensione di esecuzione è attiva. Quando l'estensione viene eliminata, l'applicazione diventa nuovamente idonea per la sospensione.

Nel secondo caso, se l'applicazione passa allo stato sospeso, rimarrà in uno stato di sospensione per il periodo dell'estensione. Una volta scaduta l'estensione, l'applicazione entra nello stato sospeso senza ulteriori notifiche.

Usare ExtendedExecutionReason.Unspecified quando si crea una ExtendedExecutionSession per richiedere tempo aggiuntivo prima che l'app si sposti in background per scenari come elaborazione multimediale, compilazione del progetto o conservazione attiva di una connessione di rete. Nei dispositivi desktop che eseguono Windows 10 nelle edizioni per desktop (Home, Pro, Enterprise ed Education), questo è l'approccio da usare se un'app non deve essere sospesa mentre è ridotta a icona.

Richiedere l'estensione all'avvio di un'operazione a esecuzione prolungata per rinviare la transizione dello stato di Sospensione che, in caso contrario, si verifica quando l'app si sposta in background. Nei dispositivi desktop, le sessioni di esecuzione estese create con ExtendedExecutionReason.Unspecified hanno un limite di tempo compatibile con la batteria. Se il dispositivo è connesso all'alimentazione a parete, non vi è alcun limite alla durata del periodo di tempo di esecuzione esteso. Se il dispositivo è alimentato a batteria, il periodo di tempo di esecuzione esteso può essere eseguito fino a dieci minuti in background.

Un utente di tablet o laptop può ottenere lo stesso comportamento a esecuzione prolungata, a scapito della durata della batteria, quando l'opzione Consenti all'app di eseguire attività in background è selezionata in Utilizzo della batteria in base alle impostazioni dell'app. (Per trovare questa impostazioni su un laptop, andare a Impostazioni>Sistema>Batteria>Uso della batteria da parte dell'app (il link sotto la percentuale di energia della battery rimanente) > selezionare un'app > disattivare Gestito da Windows> selezionare consenti all'app di eseguire attività in background.

In tutte le edizioni del sistema operativo questo tipo di sessione di esecuzione estesa si arresta quando il dispositivo entra in standby Collegato. Nei dispositivi mobili che eseguono Windows 10 Mobile, questo tipo di sessione di esecuzione estesa viene eseguito finché lo schermo è attivo. Quando lo schermo si spegne, il dispositivo tenta immediatamente di accedere alla modalità standby Connessione basso consumo. Nei dispositivi desktop la sessione continua ad essere in esecuzione se viene visualizzata la schermata di blocco. Il dispositivo non entra in stato standby Connessione per un periodo di tempo dopo la disattivazione dello schermo. In Xbox OS Edition il dispositivo entra in standby Connessione dopo un'ora, a meno che l'utente non cambi il valore predefinito.

Tracciare la posizione dell'utente.

Specificare ExtendedExecutionReason.LocationTracking quando si crea una ExtendedExecutionSession se l'app deve registrare regolarmente la posizione da GeoLocator. App per il monitoraggio e la navigazione fitness che devono monitorare regolarmente la posizione dell'utente e devono essere usate per questo motivo.

Una sessione di esecuzione estesa di rilevamento della posizione può essere eseguita fino a quando necessario, incluso mentre lo schermo è bloccato in un dispositivo mobile. Tuttavia, può esistere una sola sessione di questo tipo in esecuzione per dispositivo. Una sessione di esecuzione estesa di rilevamento della posizione può essere richiesta solo in primo piano e l'app deve trovarsi nello stato In esecuzione. In questo modo l'utente è consapevole che l'app ha avviato una sessione di rilevamento della posizione estesa. È comunque possibile usare GeoLocator mentre l'app è in background usando un'attività in background o un servizio app, senza richiedere una sessione di esecuzione estesa di rilevamento della posizione.

Salvare i dati critici in locale

Specificare ExtendedExecutionReason.SavingData quando si crea una ExtendedExecutionSession per salvare i dati utente nel caso in cui non vengano salvati i dati prima che l'app venga terminata comporterà la perdita di dati e un'esperienza utente negativa.

Non usare questo tipo di sessione per estendere la durata di un'app per caricare o scaricare dati. Se è necessario caricare i dati, richiedere un trasferimento in background o registrare un MaintenanceTrigger per gestire il trasferimento quando è disponibile l'alimentazione CA. È possibile richiedere una sessione di esecuzione estesa ExtendedExecutionReason.SavingData quando l'app è in primo piano e in stato In esecuzione oppure in background e nello stato Sospensione.

Lo stato Sospensione è l'ultima opportunità durante il ciclo di vita dell'app che un'app può eseguire prima che l'app venga terminata. ExtendedExecutionReason.SavingData è l'unico tipo di ExtendedExecutionSession che può essere richiesto nello stato In sospensione. La richiesta di una sessione di esecuzione estesa ExtendedExecutionReason.SavingData mentre l'app si trova nello stato In sospensione crea un potenziale problema di cui tenere conto. Se viene richiesta una sessione di esecuzione estesa durante lo stato Sospensione e l'utente richiede di nuovo l'avvio dell'app, potrebbe essere necessario molto tempo per l'avvio. Questo perché il periodo di tempo della sessione di esecuzione estesa deve essere completato prima che l'istanza precedente dell'app possa essere chiusa e possa essere avviata una nuova istanza dell'app. Il tempo di avvio delle prestazioni viene sacrificato per garantire che lo stato utente non venga perso.

Richiesta, eliminazione e revoca

Esistono tre interazioni fondamentali con una sessione di esecuzione estesa: la richiesta, l'eliminazione e la revoca. L'esecuzione della richiesta viene modellata nel frammento di codice seguente.

Richiedi

var newSession = new ExtendedExecutionSession();
newSession.Reason = ExtendedExecutionReason.Unspecified;
newSession.Revoked += SessionRevoked;
ExtendedExecutionResult result = await newSession.RequestExtensionAsync();

switch (result)
{
    case ExtendedExecutionResult.Allowed:
        DoLongRunningWork();
        break;

    default:
    case ExtendedExecutionResult.Denied:
        DoShortRunningWork();
        break;
}

Vedere l'esempio di codice

La chiamata a RequestExtensionAsync controlla con il sistema operativo per verificare se l'utente ha approvato l'attività in background per l'app e se il sistema dispone delle risorse disponibili per abilitare l'esecuzione in background. Una sola sessione verrà approvata per un'app in qualsiasi momento, causando la negazione di ulteriori chiamate di RequestExtensionAsync.

Si può controllare in anticipo BackgroundExecutionManager per determinare BackgroundAccessStatus, ovvero l'impostazione utente che indica se l'app può essere eseguita in background o meno. Per altre informazioni su queste impostazioni utente, vedere Background Activity and Energy Awareness.

ExtendedExecutionReason indica che l'operazione è eseguita dall'app in background. La stringa Descrizione è una stringa leggibile che spiega perché l'app deve eseguire l'operazione. Questa stringa non viene presentata all'utente, ma può essere resa disponibile in una versione futura di Windows. Il gestore eventi Revocato è necessario in modo che una sessione di esecuzione estesa possa interrompersi normalmente se l'utente o il sistema decide che l'app non può più essere eseguita in background.

Revocato

Se un'app ha una sessione di esecuzione estesa attiva e il sistema richiede l'arresto dell'attività in background perché un'applicazione in primo piano richiede le risorse, la sessione viene revocata. Un periodo di tempo della sessione in esecuzione estesa non viene mai terminato senza prima generare il gestore eventi Revocato.

Quando l'evento Revocato viene generato per una sessione di esecuzione estesa ExtendedExecutionReason.SavingData, l'app ha un secondo per completare l'operazione che stava eseguendo e terminare In sospensione.

La revoca può verificarsi per molti motivi: è stato raggiunto un limite di tempo di esecuzione, è stata raggiunta una quota di energia in background o la memoria deve essere recuperata per consentire all'utente di aprire una nuova app in primo piano.

Di seguito è riportato un esempio di gestore eventi Revocato:

private async void SessionRevoked(object sender, ExtendedExecutionRevokedEventArgs args)
{
    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
    {
        switch (args.Reason)
        {
            case ExtendedExecutionRevokedReason.Resumed:
                rootPage.NotifyUser("Extended execution revoked due to returning to foreground.", NotifyType.StatusMessage);
                break;

            case ExtendedExecutionRevokedReason.SystemPolicy:
                rootPage.NotifyUser("Extended execution revoked due to system policy.", NotifyType.StatusMessage);
                break;
        }

        EndExtendedExecution();
    });
}

Vedere l'esempio di codice

Dispose

Il passaggio finale consiste nell'eliminare la sessione di esecuzione estesa. Si vuole eliminare la sessione e qualsiasi altro asset a elevato utilizzo di memoria, perché in caso contrario l'energia usata dall'app mentre è in attesa che la sessione venga chiusa verrà conteggiata rispetto alla quota di energia dell'app. Per mantenere il maggior numero possibile di quote di energia per l'app, è importante eliminare la sessione quando si esegue il lavoro per la sessione in modo che l'app possa passare più rapidamente allo stato Sospeso.

L'eliminazione automatica della sessione, invece di attendere l'evento di revoca, riduce l'utilizzo della quota energetica dell'app. Ciò significa che l'app potrà essere eseguita in background più a lungo nelle sessioni future perché a tale scopo sarà disponibile una quota di energia maggiore. È necessario mantenere un riferimento all'oggetto ExtendedExecutionSession fino alla fine dell'operazione in modo da poter chiamare il relativo metodo Dispose.

Un frammento di codice che elimina una sessione di esecuzione estesa segue:

void ClearExtendedExecution(ExtendedExecutionSession session)
{
    if (session != null)
    {
        session.Revoked -= SessionRevoked;
        session.Dispose();
        session = null;
    }
}

Vedere l'esempio di codice

Un'app può avere un solo ExtendedExecutionSession attivo alla volta. Molte app usano attività asincrone per completare operazioni complesse che richiedono l'accesso a risorse quali archiviazione, rete o servizi basati sulla rete. Se un'operazione richiede il completamento di più attività asincrone, è necessario tenere conto dello stato di ognuna di queste attività prima di eliminare ExtendedExecutionSession e consentire la sospensione dell'app. Questo richiede il conteggio del numero di attività ancora in esecuzione e non di eliminazione della sessione fino a quando tale valore non raggiunge lo zero.

Di seguito è riportato un esempio di codice per la gestione di più attività durante un periodo di sessione di esecuzione esteso. Per altre informazioni su come usarlo nell'app, vedere l'esempio di codice collegato di seguito:

static class ExtendedExecutionHelper
{
    private static ExtendedExecutionSession session = null;
    private static int taskCount = 0;

    public static bool IsRunning
    {
        get
        {
            if (session != null)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }

    public static async Task<ExtendedExecutionResult> RequestSessionAsync(ExtendedExecutionReason reason, TypedEventHandler<object, ExtendedExecutionRevokedEventArgs> revoked, String description)
    {
        // The previous Extended Execution must be closed before a new one can be requested.       
        ClearSession();

        var newSession = new ExtendedExecutionSession();
        newSession.Reason = reason;
        newSession.Description = description;
        newSession.Revoked += SessionRevoked;

        // Add a revoked handler provided by the app in order to clean up an operation that had to be halted prematurely
        if(revoked != null)
        {
            newSession.Revoked += revoked;
        }

        ExtendedExecutionResult result = await newSession.RequestExtensionAsync();

        switch (result)
        {
            case ExtendedExecutionResult.Allowed:
                session = newSession;
                break;
            default:
            case ExtendedExecutionResult.Denied:
                newSession.Dispose();
                break;
        }
        return result;
    }

    public static void ClearSession()
    {
        if (session != null)
        {
            session.Dispose();
            session = null;
        }

        taskCount = 0;
    }

    public static Deferral GetExecutionDeferral()
    {
        if (session == null)
        {
            throw new InvalidOperationException("No extended execution session is active");
        }

        taskCount++;
        return new Deferral(OnTaskCompleted);
    }

    private static void OnTaskCompleted()
    {
        if (taskCount > 0)
        {
            taskCount--;
        }
        
        //If there are no more running tasks than end the extended lifetime by clearing the session
        if (taskCount == 0 && session != null)
        {
            ClearSession();
        }
    }

    private static void SessionRevoked(object sender, ExtendedExecutionRevokedEventArgs args)
    {
        //The session has been prematurely revoked due to system constraints, ensure the session is disposed
        if (session != null)
        {
            session.Dispose();
            session = null;
        }
        
        taskCount = 0;
    }
}

Vedere l'esempio di codice

Assicurarsi che l'app usi correttamente le risorse

L'ottimizzazione della memoria e dell'uso dell'energia dell'app è fondamentale per garantire che il sistema operativo consenta all'app di continuare l'esecuzione quando non è più l'app in primo piano. Usare le API di gestione della memoria per verificare la quantità di memoria usata dall'app. Maggiore è la quantità di memoria usata dall'app, più è difficile che il sistema operativo mantenga l'app in esecuzione quando un'altra app è in primo piano. L'utente ha in definitiva il controllo di tutte le attività in background che l'app può eseguire e ha visibilità sull'impatto che l'app ha sull'uso della batteria.

Usare BackgroundExecutionManager.RequestAccessAsync per determinare se l'utente ha deciso che l'attività in background dell'app deve essere limitata. Tenere presente l'utilizzo della batteria ed eseguire in background solo quando è necessario completare un'azione desiderata dall'utente.

Vedi anche

Esempio di esecuzione estesa
Ciclo di vita di un'applicazione
Ciclo di vita dell'app - Mantenere attive le app con attività in background egestione della memoria in background per l'esecuzione estesa
Trasferimenti in background
Consapevolezza della batteria e attività in background
Classe MemoryManager
Riprodurre elementi multimediali in background