Limiti di esecuzione in background

Ogni volta che un'app viene eseguita in background, consuma alcune delle risorse limitate del dispositivo, come la RAM. Ciò può comportare un'esperienza utente ridotta, soprattutto se l'utente utilizza un'app che richiede molte risorse, ad esempio giocando a un gioco o guardando un video. Per migliorare l'esperienza utente, Android 8.0 (livello API 26) impone limitazioni alle azioni che le app possono svolgere durante l'esecuzione in background. Questo documento descrive le modifiche al sistema operativo e come puoi aggiornare la tua app in modo che funzioni correttamente in base alle nuove limitazioni.

Panoramica

Molti servizi e app Android possono essere eseguiti contemporaneamente. Ad esempio, un utente potrebbe giocare a un gioco in una finestra mentre naviga sul web in un'altra finestra e utilizzare una terza app per riprodurre musica. Più app vengono eseguite contemporaneamente, maggiore è il carico sul sistema. Se altre app o altri servizi sono in esecuzione in background, il sistema viene sottoposto a un carico aggiuntivo, che potrebbe comportare una scarsa esperienza utente. Ad esempio, l'app di musica potrebbe essere improvvisamente chiusa.

Per ridurre la possibilità di questi problemi, Android 8.0 impone limitazioni a ciò che le app possono fare quando gli utenti non interagiscono direttamente con esse. Le app sono limitate in due modi:

  • Limitazioni dei servizi in background: quando un'app è inattiva, esistono limiti all'utilizzo dei servizi in background. Questo non vale per i servizi in primo piano, che sono più evidenti per l'utente.

  • Limitazioni di trasmissione: con alcune eccezioni, le app non possono usare il proprio manifest per registrarsi per le trasmissioni implicite. Possono comunque registrarsi per queste trasmissioni in fase di esecuzione e utilizzare il manifest per registrarsi per le trasmissioni esplicite e quelle mirate specificamente alla loro app.

Nella maggior parte dei casi, le app possono aggirare queste limitazioni utilizzando i job JobScheduler. Questo approccio consente a un'app di eseguire operazioni quando non è in esecuzione, ma offre comunque al sistema la possibilità di pianificare questi job in modo da non influire sull'esperienza utente. Android 8.0 offre diversi miglioramenti a JobScheduler che semplificano la sostituzione di servizi e broadcast receiver con job pianificati. Per ulteriori informazioni, consulta Miglioramenti a JobScheduler.

Limitazioni dei servizi in background

I servizi in esecuzione in background possono consumare le risorse del dispositivo, con un possibile peggioramento dell'esperienza utente. Per ovviare a questo problema, il sistema applica una serie di limitazioni ai servizi.

Il sistema distingue tra app in primo piano e in background. La definizione di background ai fini delle limitazioni del servizio è diversa da quella utilizzata dalla gestione della memoria; un'app potrebbe essere in background per quanto riguarda la gestione della memoria, ma in primo piano per quanto riguarda la sua capacità di avviare servizi. Un'app è considerata in primo piano se una delle seguenti condizioni è vera:

  • Ha un'attività visibile, indipendentemente dal fatto che sia avviata o in pausa.
  • Ha un servizio in primo piano.
  • Un'altra app in primo piano è collegata all'app tramite l'associazione a uno dei suoi servizi o tramite l'utilizzo di uno dei suoi fornitori di contenuti. Ad esempio, l'app è in primo piano se un'altra app si lega ai suoi:
    • IME
    • Servizio di sfondi
    • Listener di notifica
    • Servizio vocale o di messaggistica

Se nessuna di queste condizioni è vera, l'app è considerata in background.

Quando un'app è in primo piano, può creare ed eseguire liberamente sia i servizi in primo piano sia quelli in background. Quando un'app passa in background, ha un periodo di diversi minuti in cui è ancora consentito creare e utilizzare servizi. Al termine di questo periodo, l'app viene considerata inattiva. A questo punto, il sistema interrompe i servizi in background dell'app, come se l'app avesse chiamato i metodi Service.stopSelf() dei servizi.

In determinate circostanze, un'app in background viene inserita in una lista consentita temporanea per diversi minuti. Quando un'app è nella lista consentita, può avviare servizi senza limitazioni e i suoi servizi in background sono autorizzati a funzionare. Un'app viene inserita nella lista consentita quando gestisce un'attività visibile all'utente, ad esempio:

In molti casi, l'app può sostituire i servizi in background con job JobScheduler. Ad esempio, CoolPhotoApp deve verificare se l'utente ha ricevuto foto condivise dagli amici, anche se l'app non è in esecuzione in primo piano. In precedenza, l'app utilizzava un servizio in background che faceva riferimento allo spazio di archiviazione sul cloud dell'app. Per eseguire la migrazione ad Android 8.0 (livello API 26), lo sviluppatore sostituisce il servizio in background con un job pianificato, che viene avviato periodicamente, esegue query sul server e poi esce.

Prima di Android 8.0, il modo consueto per creare un servizio in primo piano era creare un servizio in background e poi promuoverlo in primo piano. Con Android 8.0 c'è una complicazione: il sistema non consente a un'app in background di creare un servizio in background. Per questo motivo, Android 8.0 introduce il nuovo metodo startForegroundService() per avviare un nuovo servizio in primo piano. Dopo che il sistema ha creato il servizio, l'app ha cinque secondi di tempo per chiamare il metodo [startForeground()](/reference/android/app/Service#startForeground(int, android.app.Notification) del servizio per mostrare la notifica visibile all'utente del nuovo servizio. Se l'app non chiama startForeground() entro il limite di tempo, il sistema interrompe il servizio e dichiara l'app come ANR.

Limitazioni di trasmissione

Se un'app si registra per ricevere le trasmissioni, il relativo destinatario consuma risorse ogni volta che viene inviata una trasmissione. Ciò può causare problemi se troppe app si registrano per ricevere le trasmissioni in base agli eventi di sistema. Un evento di sistema che attiva una trasmissione può causare il consumo di risorse da parte di tutte queste app in rapida successione, compromettendo l'esperienza utente. Per ovviare a questo problema, Android 7.0 (livello API 24) ha imposto limitazioni alle trasmissioni, come descritto in Ottimizzazione in background. Android 8.0 (livello API 26) rende queste limitazioni più stringenti.

  • Le app che hanno come target Android 8.0 o versioni successive non possono più registrare broadcast receiver per le trasmissioni implicite nel file manifest, a meno che la trasmissione non sia limitata specificamente a quell'app. Una trasmissione implicita è una trasmissione che non ha come target un componente specifico all'interno di un'app. Ad esempio, ACTION_PACKAGE_REPLACED viene inviata a tutti gli ascoltatori registrati in tutte le app per informarli che un pacchetto sul dispositivo è stato sostituito. Poiché la trasmissione è implicita, non verrà inviata ai destinatari registrati nel file manifest nelle app che hanno come target Android 8.0 o versioni successive. ACTION_MY_PACKAGE_REPLACED è anche una trasmissione implicita, ma poiché viene inviata solo all'app il cui package è stato sostituito, verrà recapitata ai destinatari registrati nel manifest.
  • Le app possono continuare a registrarsi per le trasmissioni esplicite nei manifest.
  • Le app possono utilizzare Context.registerReceiver() in fase di esecuzione per registrare un ricevitore per qualsiasi trasmissione, implicita o esplicita.
  • Le trasmissioni che richiedono un'autorizzazione di firma sono esenti da questa limitazione, poiché vengono inviate solo alle app firmate con lo stesso certificato, non a tutte le app sul dispositivo.

In molti casi, le app che in precedenza si sono registrate per una trasmissione implicita possono ottenere funzionalità simili utilizzando un job JobScheduler. Ad esempio, un'app di foto social potrebbe dover eseguire di tanto in tanto la pulizia dei propri dati e preferire farlo quando il dispositivo è collegato a un caricabatterie. In precedenza, l'app registrava un ricevitore per ACTION_POWER_CONNECTED nel suo manifest. Quando l'app riceveva la trasmissione, controllava se era necessaria la pulizia. Per eseguire la migrazione ad Android 8.0 o versioni successive, l'app rimuove il ricevitore dal suo manifest. L'app pianifica invece un job di pulizia che viene eseguito quando il dispositivo è inattivo e in carica.

Guida alla migrazione

Per impostazione predefinita, queste modifiche interessano solo le app che hanno come target Android 8.0 (livello API 26) o versioni successive. Tuttavia, gli utenti possono attivare queste restrizioni per qualsiasi app dalla schermata Impostazioni, anche se l'app ha come target un livello API inferiore a 26. Potresti dover aggiornare l'app per conformarti alle nuove limitazioni.

Controlla in che modo la tua app utilizza i servizi. Se la tua app si basa su servizi che vengono eseguiti in background quando non è in uso, dovrai sostituirli. Ecco alcune possibili soluzioni:

  • Se la tua app deve creare un servizio in primo piano mentre è in background, utilizza il metodo startForegroundService() anziché startService().
  • Se il servizio è rilevabile dall'utente, impostalo come servizio in primo piano. Ad esempio, un servizio che riproduce audio deve sempre essere un servizio in primo piano. Crea il servizio utilizzando il metodo startForegroundService() instead of startService().
  • Trova un modo per duplicare la funzionalità del servizio con un job pianificato. Se il servizio non esegue un'azione immediatamente visibile all'utente, in genere dovresti poter utilizzare un job pianificato.
  • Utilizza FCM per riattivare selettivamente la tua applicazione quando si verificano eventi di rete, anziché eseguire il polling in background.
  • Rimandare il lavoro in background finché l'applicazione non è naturalmente in primo piano.

Esamina i broadcast receiver definiti nel file manifest dell'app. Se il manifest dichiara un ricevitore per una trasmissione implicita interessata, devi sostituirlo. Ecco alcune possibili soluzioni:

  • Crea il ricevitore in fase di esecuzione chiamando Context.registerReceiver() anziché dichiararlo nel file manifest.
  • Utilizza un job pianificato per verificare la condizione che avrebbe attivato la trasmissione implicita.