Limitazioni di sistema per le attività in background

I processi in background possono richiedere un utilizzo intensivo della memoria e della batteria. Ad esempio, una trasmissione implicita può avviare molti processi in background registrati per ascoltarla, anche se questi processi potrebbero non svolgere molto lavoro. Questo può avere un impatto significativo sia sulle prestazioni del dispositivo sia sull'esperienza utente.

Per evitare le limitazioni del sistema, assicurati di utilizzare l'API corretta per l'attività in background. La documentazione Panoramica delle attività in background ti aiuta a scegliere l'API giusta per le tue esigenze.

Limitazioni avviate dall'utente

Se un'app mostra alcuni dei comportamenti errati descritti 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 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 è destinata a 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 allarmi o utilizzare la rete, tranne quando l'app è in primo piano.

Limitazioni alla ricezione delle trasmissioni di attività di rete

Le app non ricevono le trasmissioni CONNECTIVITY_ACTION se si registrano per riceverle nel manifest e i processi che dipendono da questa trasmissione non vengono avviati. Questo potrebbe rappresentare un problema per le app che vogliono ascoltare le modifiche di 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.

Pianificare il lavoro sulle 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 doWork() metodo 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ù affidabile per richiedere un callback solo quando vengono soddisfatte le condizioni di rete specificate.

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

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

Limitazioni alla ricezione delle trasmissioni di immagini e video

Le app non sono in grado di inviare o ricevere ACTION_NEW_PICTURE o ACTION_NEW_VIDEO trasmissioni. Questa limitazione contribuisce ad alleviare l'impatto sulle prestazioni e sull'esperienza utente quando diverse app devono essere attivate per elaborare una nuova immagine o un nuovo video.

Determinare quali autorità di contenuti hanno attivato il lavoro

WorkerParameters consente alla tua app di ricevere informazioni utili sulle autorità di contenuti e sugli URI che hanno attivato il lavoro:

List<Uri> getTriggeredContentUris()

Restituisce un elenco di URI che hanno attivato il lavoro. Questo elenco è vuoto se nessun URI ha attivato il lavoro (ad esempio, il lavoro è stato attivato a causa di una scadenza o per qualche altro motivo) o se il numero di URI modificati è superiore a 50.

List<String> getTriggeredContentAuthorities()

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

Il seguente codice campione esegue l'override del CoroutineWorker.doWork() metodo e registra le autorità di contenuti e gli URI 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()
    }
}

Testare l'app in base alle limitazioni del sistema

L'ottimizzazione delle app per l'esecuzione su dispositivi con poca memoria o in condizioni di poca memoria può migliorare le prestazioni e l'esperienza utente. La rimozione delle dipendenze dai servizi in background e dai ricevitori di trasmissioni implicite registrati nel manifest può aiutare l'app a funzionare meglio 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 le 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

Ottimizzare ulteriormente l'app

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