Limitazioni di sistema relative al lavoro in background

I processi in background possono consumare memoria e batteria. Ad esempio, una trasmissione implicita può avviare molti processi in background che sono stati registrati per ascoltarla, anche se questi processi potrebbero non funzionare correttamente. Ciò può avere un impatto significativo sia sulle prestazioni del dispositivo sia sull'esperienza utente.

Per evitare limitazioni di sistema, assicurati di utilizzare l'API giusta per l'attività in background. La documentazione sulla panoramica delle attività in background ti aiuta a scegliere l'API giusta per le 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 un utilizzo eccessivo di risorse, avvisa l'utente e offre la possibilità di limitare le azioni dell'app. I comportamenti che possono attivare la notifica includono:

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

Le restrizioni precise imposte sono stabilite dal produttore del dispositivo. Ad esempio, nelle build AOSP, le app con limitazioni non possono eseguire job, attivare allarmi o utilizzare la rete, tranne quando l'app è in primo piano.

Limitazioni relative alla ricezione di trasmissioni delle attività di rete

Le app non ricevono broadcast CONNECTIVITY_ACTION se si registrano per riceverli nel loro file manifest e i processi che dipendono da questa trasmissione non verranno avviati. Questo potrebbe rappresentare un problema per le app che vogliono rimanere in ascolto delle modifiche alla rete o eseguire attività di rete collettive quando il dispositivo si connette a una rete unmetered. Nel framework Android esistono già diverse soluzioni per aggirare questa limitazione, ma la scelta quella giusta dipende dall'obiettivo che vuoi far eseguire all'app.

Programma il lavoro sulle connessioni unmetere

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 offre un metodo più affidabile per richiedere un callback solo quando sono soddisfatte le condizioni di rete specificate.

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

L'app continua a ricevere callback fino a quando non esce dall'app o non chiama unregistraNetworkCallback().

Limitazioni relative alla ricezione di trasmissioni di immagini e video

Le app non sono in grado di inviare o ricevere trasmissioni ACTION_NEW_PICTURE o ACTION_NEW_VIDEO. Questa limitazione contribuisce a ridurre l'impatto sulle prestazioni e sull'esperienza utente quando è necessario attivare più app per elaborare una nuova immagine o un nuovo video.

Stabilire quali autorità di contenuti hanno attivato l'operatività

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

List<Uri> getTriggeredContentUris()

Restituisce un elenco di URI che hanno attivato l'elaborazione. Questo campo è vuoto se nessun URI ha attivato il lavoro (ad esempio se il lavoro è stato attivato a causa di una scadenza o per altri motivi) oppure se il numero di URI modificati è maggiore di 50.

List<String> getTriggeredContentAuthorities()

Restituisce un elenco di stringhe delle autorità di contenuto che hanno attivato l'operazione. Se l'elenco restituito non è vuoto, utilizza getTriggeredContentUris() per recuperare i dettagli di quali URI sono stati modificati.

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

class MyWorker(
    appContext: Context,
    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 in base alle limitazioni di sistema

Se ottimizzi le tue app per eseguirle su dispositivi con memoria ridotta o in condizioni di scarsa memoria, puoi migliorare le prestazioni e l'esperienza utente. La rimozione delle dipendenze dai servizi in background e dai ricevitori di trasmissione impliciti registrati con manifest può consentire alla tua app di funzionare meglio su questi dispositivi. Ti consigliamo di ottimizzare l'app in modo che venga eseguita senza utilizzare questi processi in background.

Alcuni comandi Android Debug Bridge (ADB) aggiuntivi possono aiutarti a testare il comportamento dell'app quando i processi in background sono disabilitati:

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

    $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignore

  • Per riattivare le trasmissioni e i servizi in background impliciti, 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 relativa all'ottimizzazione dell'utilizzo della batteria per le API di pianificazione delle attività.