Limitazioni di sistema per le attività in background

I processi in background possono consumare molta memoria e batteria. Ad esempio, una trasmissione implicita potrebbe avviare molti processi in background che si sono registrati per ascoltarla, anche se questi processi potrebbero non svolgere molto lavoro. Ciò può avere un impatto sostanziale sia sulle prestazioni del dispositivo sia sull'esperienza utente.

Per evitare limitazioni del sistema, assicurati di utilizzare l'API corretta per la tua attività in background. La documentazione della panoramica delle attività in background ti aiuta a scegliere l'API più adatta alle tue esigenze.

Limitazioni avviate dall'utente

Se un'app mostra alcune delle prestazioni scadenti descritte in Android vitals, il sistema chiede all'utente di limitare l'accesso dell'app alle risorse di sistema.

Se il sistema rileva che un'app sta consumando risorse eccessive, invia una notifica all'utente e gli offre la possibilità di limitare le azioni dell'app. I comportamenti che possono attivare l'avviso includono:

  1. Wakelock eccessivi: un wakelock parziale mantenuto per un'ora quando lo schermo è disattivato
  2. Servizi in background eccessivi: se l'app ha come target livelli API inferiori a 26 e ha servizi in background eccessivi

Le limitazioni precise imposte sono determinate dal produttore del dispositivo. Ad esempio, nelle build AOSP, le app con limitazioni non possono eseguire job, attivare sveglie o utilizzare la rete, a meno che l'app non sia in primo piano.

Limitazioni alla ricezione di trasmissioni di attività di rete

Le app non ricevono le trasmissioni CONNECTIVITY_ACTION se si registrano per riceverle nel loro manifest e i processi che dipendono da questa trasmissione non verranno avviati. Questo potrebbe rappresentare un problema per le app che vogliono rilevare le modifiche alla rete o eseguire attività di rete collettive quando il dispositivo si connette a una rete non a consumo. Nel framework Android esistono già diverse soluzioni per aggirare questa limitazione, ma la scelta di quella giusta dipende da ciò che vuoi che la tua app realizzi.

Pianifica il lavoro su connessioni non a consumo

Quando crei un WorkRequest, aggiungi un Constraint NetworkType.UNMETERED.

fun scheduleWork(context: Context) {
    val workManager = WorkManager.getInstance(context)
    val workRequest = OneTimeWorkRequestBuilder<MyWorker>()
        .setConstraints(
            Constraints.Builder()
                .setRequiredNetworkType(NetworkType.UNMETERED)
                .build()
        )
        .build()

    workManager.enqueue(workRequest)
}

Quando le condizioni per il tuo lavoro sono soddisfatte, la tua app riceve un callback per eseguire il metodo doWork() nella classe Worker specificata.

Monitorare la connettività di rete mentre l'app è in esecuzione

Le app in esecuzione possono comunque ascoltare CONNECTIVITY_CHANGE con un BroadcastReceiver registrato. Tuttavia, l'API ConnectivityManager fornisce un metodo più efficace per richiedere un callback solo quando vengono soddisfatte determinate condizioni di rete.

Gli oggetti NetworkRequest definiscono i parametri del callback di rete in termini di NetworkCapabilities. Puoi creare oggetti NetworkRequest con la classe NetworkRequest.Builder. registerNetworkCallback passa quindi l'oggetto NetworkRequest al sistema. Quando le condizioni della rete sono soddisfatte, l'app riceve un callback per eseguire il metodo onAvailable() definito nella classe ConnectivityManager.NetworkCallback.

L'app continua a ricevere callback finché non viene chiusa o non chiama unregisterNetworkCallback().

Limitazioni alla ricezione di trasmissioni di immagini e video

Le app non possono inviare o ricevere trasmissioni ACTION_NEW_PICTURE o ACTION_NEW_VIDEO. Questa limitazione contribuisce ad attenuare l'impatto sulle prestazioni e sull'esperienza utente quando più app devono attivarsi per elaborare una nuova immagine o un nuovo video.

Determinare quali autorità dei contenuti hanno attivato il lavoro

WorkerParameters consente alla tua app di ricevere informazioni utili su quali autorità dei contenuti e URI hanno attivato il lavoro:

List<Uri> getTriggeredContentUris()

Restituisce un elenco di URI che hanno attivato il lavoro. Questo campo è vuoto se nessun URI ha attivato l'attività (ad esempio, l'attività è stata attivata a causa di una scadenza o per un altro motivo) o se il numero di URI modificati è maggiore di 50.

List<String> getTriggeredContentAuthorities()

Restituisce un elenco di stringhe di autorità dei contenuti che hanno attivato il lavoro. Se l'elenco restituito non è vuoto, utilizza getTriggeredContentUris() per recuperare i dettagli degli URI che sono stati modificati.

Il seguente codice campione esegue l'override del metodo CoroutineWorker.doWork() e registra le autorità dei contenuti e gli URI che hanno attivato il job:

class MyWorker(
    appContext: Context,
    private val params: WorkerParameters
) : CoroutineWorker(appContext, params) {
    override suspend fun doWork(): Result {
        StringBuilder().apply {
            append("Media content has changed:\n")
            params.triggeredContentAuthorities
                .takeIf { it.isNotEmpty() }
                ?.let { authorities ->
                    append("Authorities: ${authorities.joinToString(", ")}\n")
                    append(params.triggeredContentUris.joinToString("\n"))
                } ?: append("(No content)")
            Log.i(TAG, toString())
        }
        return Result.success()
    }
}

Testa l'app con le limitazioni di sistema

L'ottimizzazione delle app per l'esecuzione su dispositivi con memoria ridotta o in condizioni di memoria ridotta può migliorare le prestazioni e l'esperienza utente. La rimozione delle dipendenze dai servizi in background e dai broadcast receiver per trasmissione implicita registrati nel manifest può contribuire a migliorare il funzionamento dell'app su questi dispositivi. Ti consigliamo di ottimizzare l'app in modo che venga eseguita senza l'utilizzo di questi processi in background.

Alcuni comandi aggiuntivi di Android Debug Bridge (ADB) possono aiutarti a testare il comportamento dell'app con questi processi in background disattivati:

  • Per simulare condizioni in cui le trasmissioni implicite e i servizi in background non sono disponibili, inserisci il seguente comando:

    $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignore

  • Per riattivare le trasmissioni implicite e i servizi in background, inserisci il seguente comando:

    $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow

Ottimizza ulteriormente la tua app

Per altri modi efficaci per ottimizzare il comportamento delle attività in background, consulta la documentazione Ottimizza l'utilizzo della batteria per le API di pianificazione delle attività.