Ottimizzazione in background

I processi in background possono richiedere molta memoria e batteria. Ad esempio, un la trasmissione implicita può avviare molti processi in background registrati per ascoltarli, anche se questi processi potrebbero non funzionare molto. Questo può avere un impatto significativo sia sulle prestazioni del dispositivo sia sull'esperienza utente.

Per ovviare a questo problema, Android 7.0 (livello API 24) applica quanto segue: restrizioni:

Se la tua app utilizza uno di questi intent, devi rimuovere le dipendenze il prima possibile per poter scegliere correttamente come target i dispositivi con Android 7.0 o superiore. Il framework Android offre diverse soluzioni per mitigare necessarie per queste trasmissioni implicite. Ad esempio, JobScheduler e il nuovo WorkManager offre meccanismi solidi per pianificare operazioni in condizioni specificate, ad esempio una connessione a un siano soddisfatti. Ora puoi usare anche JobScheduler per reagire alle modifiche ai fornitori di contenuti. JobInfo gli oggetti incapsulano i parametri JobScheduler per pianificare il job. Quando le condizioni del job sono soddisfatte, il sistema esegue questo job sul JobService della tua app.

In questa pagina impareremo a utilizzare metodi alternativi, come JobScheduler, per adattare la tua app a queste nuove limitazioni.

Limitazioni avviate dall'utente

Nella pagina Utilizzo batteria all'interno del sistema impostazioni, l'utente può scegli una delle seguenti opzioni:

  • Senza limitazioni. Consenti tutto il lavoro in background, che potrebbe consumare più batteria.
  • Ottimizzato (impostazione predefinita): ottimizza la capacità di un'app di eseguire il lavoro in background. in base a come l'utente interagisce con l'app.
  • Con limitazioni:impedisce completamente l'esecuzione di un'app in background. App potrebbe non funzionare come previsto.
di Gemini Advanced.

Se un'app presenta alcuni dei comportamenti dannosi descritti in Android vitals, il sistema potrebbe richiedere all'utente di limitare l'accesso dell'app alle risorse di sistema.

Se il sistema rileva un consumo eccessivo di risorse, invia una notifica l'utente, offrendogli la possibilità di limitare le azioni dell'app. I comportamenti che possono attivare la notifica includono:

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

Le precise limitazioni imposte sono stabilite dal produttore del dispositivo. Per Ad esempio, sulle build AOSP con Android 9 (livello API 28) o versioni successive, le app in esecuzione in background che si trovano nella zona "limitata" hanno le seguenti caratteristiche: limitazioni:

  • Impossibile avviare i servizi in primo piano
  • I servizi in primo piano esistenti vengono rimossi da quello in primo piano
  • Le sveglie non vengono attivate
  • I job non vengono eseguiti

Inoltre, se un'app ha come target Android 13 (livello API 33) o versioni successive e si trova nel "limitato" stato, il sistema non trasmette la trasmissione BOOT_COMPLETED o la trasmissione LOCKED_BOOT_COMPLETED fino all'avvio dell'app per altri motivi.

Le limitazioni specifiche sono elencate in Limitazioni relative alla gestione dell'alimentazione.

Limitazioni relative alla ricezione di annunci di attività di rete

Le app che hanno come target Android 7.0 (livello API 24) non ricevono annunci da CONNECTIVITY_ACTION se registrarsi per riceverle nel file manifest, e i processi che dipendono da questo la trasmissione non verrà avviata. Questo potrebbe rappresentare un problema per le app che vogliono di ascoltare le modifiche di rete o eseguire attività di rete collettive quando dispositivo si connette a una rete unmetered. Diverse soluzioni per aggirare questo problema limitazione esiste già nel framework Android, ma scegliere la giusta dipende da ciò che vuoi che compi la tua app.

Nota: un BroadcastReceiver registrato con Context.registerReceiver() continua a ricevere questi annunci mentre l'app è in esecuzione.

Pianifica job di rete su connessioni unmetered

Quando utilizzi il corso JobInfo.Builder per creare l'oggetto JobInfo, applica il metodo setRequiredNetworkType() e passa JobInfo.NETWORK_TYPE_UNMETERED come parametro del job. Il seguente esempio di codice pianifica l'esecuzione di un servizio quando il dispositivo si connette a un rete e in carica:

Kotlin

const val MY_BACKGROUND_JOB = 0
...
fun scheduleJob(context: Context) {
    val jobScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
    val job = JobInfo.Builder(
            MY_BACKGROUND_JOB,
            ComponentName(context, MyJobService::class.java)
    )
            .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
            .setRequiresCharging(true)
            .build()
    jobScheduler.schedule(job)
}

Java

public static final int MY_BACKGROUND_JOB = 0;
...
public static void scheduleJob(Context context) {
  JobScheduler js =
      (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
  JobInfo job = new JobInfo.Builder(
    MY_BACKGROUND_JOB,
    new ComponentName(context, MyJobService.class))
      .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
      .setRequiresCharging(true)
      .build();
  js.schedule(job);
}

Quando le condizioni del job sono soddisfatte, l'app riceve un callback che viene eseguita il metodo onStartJob() nel JobService.class specificato. Per visualizzare altri esempi di implementazione di JobScheduler, consulta l'app di esempio JobScheduler.

Una nuova alternativa a JobScheduler è WorkManager, un'API che consente di pianificare di attività in background che richiedono il completamento garantito, indipendentemente dal fatto che il processo dell'app sia presente o meno. Responsabile del lavoro sceglie il modo appropriato per eseguire il lavoro (direttamente su un thread nel processo dell'app, nonché l'utilizzo di JobScheduler, FirebaseJobDispatcher o HourManager) in base a fattori quali livello API del dispositivo. Inoltre, WorkManager non richiede Play Services e fornisce diverse funzionalità avanzate, come il concatenamento delle attività o il controllo dello stato di un'attività. Per ulteriori informazioni vedi WorkManager.

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

Le app in esecuzione possono comunque ascoltare CONNECTIVITY_CHANGE con un registrato BroadcastReceiver. Tuttavia, l'API ConnectivityManager offre un metodo più affidabile per le richieste a un callback solo quando sono soddisfatte le condizioni di rete specificate.

Gli oggetti NetworkRequest definiscono i parametri di callback di rete in termini di NetworkCapabilities. Tu crea oggetti NetworkRequest con la classe NetworkRequest.Builder. registerNetworkCallback() poi passa l'oggetto NetworkRequest al sistema. Quando se le condizioni di rete sono soddisfatte, l'app riceve un callback per eseguire Metodo onAvailable() definito nella relativa classe ConnectivityManager.NetworkCallback.

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

Limitazioni relative alla ricezione di trasmissioni di immagini e video

In Android 7.0 (livello API 24), le app non possono inviare o ricevere annunci ACTION_NEW_PICTURE o ACTION_NEW_VIDEO. Questa restrizione consente ridurre gli impatti sulle prestazioni e sull'esperienza utente quando più app devono per elaborare una nuova immagine o un nuovo video. Android 7.0 (livello API 24) estende JobInfo e JobParameters per fornire una soluzione alternativa.

Attiva job in caso di modifiche all'URI dei contenuti

Per attivare job in caso di modifiche all'URI dei contenuti, Android 7.0 (livello API 24) estende l'API JobInfo con i seguenti metodi:

JobInfo.TriggerContentUri()
Incapsula i parametri necessari per attivare un job in caso di modifiche all'URI dei contenuti.
JobInfo.Builder.addTriggerContentUri()
Passa un oggetto TriggerContentUri a JobInfo. ContentObserver monitora l'URI dei contenuti incapsulati. Se a un job sono associati più oggetti TriggerContentUri, il sistema fornisce un'istanza anche se segnala una modifica in uno solo degli URI dei contenuti.
di Gemini Advanced.
Aggiungi il flag TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS a attiva il job in caso di modifica dei discendenti dell'URI specificato. Questo flag corrisponde al parametro notifyForDescendants passato a registerContentObserver().

Nota: TriggerContentUri() non può essere utilizzato in in combinazione con setPeriodic() o setPersisted(). Per monitorare continuamente le modifiche dei contenuti, pianifica una nuova JobInfo prima che il dispositivo JobService dell'app finisca di gestire la richiamata più recente.

Il seguente codice di esempio pianifica l'attivazione di un job quando il sistema Una modifica all'URI dei contenuti, MEDIA_URI:

Kotlin

const val MY_BACKGROUND_JOB = 0
...
fun scheduleJob(context: Context) {
    val jobScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
    val job = JobInfo.Builder(
            MY_BACKGROUND_JOB,
            ComponentName(context, MediaContentJob::class.java)
    )
            .addTriggerContentUri(
                    JobInfo.TriggerContentUri(
                            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                            JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS
                    )
            )
            .build()
    jobScheduler.schedule(job)
}

Java

public static final int MY_BACKGROUND_JOB = 0;
...
public static void scheduleJob(Context context) {
  JobScheduler js =
          (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
  JobInfo.Builder builder = new JobInfo.Builder(
          MY_BACKGROUND_JOB,
          new ComponentName(context, MediaContentJob.class));
  builder.addTriggerContentUri(
          new JobInfo.TriggerContentUri(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
          JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS));
  js.schedule(builder.build());
}

Quando il sistema segnala una modifica degli URI dei contenuti specificati, la tua app riceve un callback e un oggetto JobParameters passato a onStartJob() in MediaContentJob.class.

Determinare quali autorità dei contenuti hanno attivato un job

Android 7.0 (livello API 24) estende anche JobParameters a consentire alla tua app di ricevere informazioni utili su quali autorità di contenuto e URI hanno attivato il job:

Uri[] getTriggeredContentUris()
Restituisce un array di URI che hanno attivato il job. Il valore sarà null se nessun URI ha attivato il job (ad esempio, il job è attivato per una scadenza o per altri motivi) oppure il numero di modifiche Il numero di URI è maggiore di 50.
String[] getTriggeredContentAuthorities()
Restituisce un array di stringhe di autorità sui contenuti che hanno attivato il job. Se l'array restituito non è null, utilizza getTriggeredContentUris() per recuperare i dettagli degli URI modificati.

Il seguente codice campione esegue l'override del metodo JobService.onStartJob() e registra le autorità relative ai contenuti e gli URI che hanno attivato il job:

Kotlin

override fun onStartJob(params: JobParameters): Boolean {
    StringBuilder().apply {
        append("Media content has changed:\n")
        params.triggeredContentAuthorities?.also { authorities ->
            append("Authorities: ${authorities.joinToString(", ")}\n")
            append(params.triggeredContentUris?.joinToString("\n"))
        } ?: append("(No content)")
        Log.i(TAG, toString())
    }
    return true
}

Java

@Override
public boolean onStartJob(JobParameters params) {
  StringBuilder sb = new StringBuilder();
  sb.append("Media content has changed:\n");
  if (params.getTriggeredContentAuthorities() != null) {
      sb.append("Authorities: ");
      boolean first = true;
      for (String auth :
          params.getTriggeredContentAuthorities()) {
          if (first) {
              first = false;
          } else {
             sb.append(", ");
          }
           sb.append(auth);
      }
      if (params.getTriggeredContentUris() != null) {
          for (Uri uri : params.getTriggeredContentUris()) {
              sb.append("\n");
              sb.append(uri);
          }
      }
  } else {
      sb.append("(No content)");
  }
  Log.i(TAG, sb.toString());
  return true;
}

Ottimizza ulteriormente la tua app

Ottimizzare le app in modo che vengano eseguite su dispositivi con memoria ridotta o scarsa possono migliorare le prestazioni e l'esperienza utente. Rimozione in corso... di dipendenze sui servizi in background e sulle corrispondenze implicite registrate i broadcast receiver possono aiutare la tua app a funzionare meglio su questi dispositivi. Sebbene Android 7.0 (livello API 24) adotta misure per ridurre alcuni di questi problemi, ti consigliamo di ottimizzare l'app in modo che venga eseguita senza utilizzare questi processi in background completamente.

Il seguente Android Debug Bridge (ADB) possono aiutarti a testare il comportamento dell'app se i processi in background sono disattivati:

  • Per simulare condizioni in cui trasmissioni e servizi in background impliciti 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
    
  • Puoi simulare l'inserimento dell'app nell'elenco "limitato" stato per l'utilizzo della batteria in background. Questa impostazione impedisce l'esecuzione dell'app in background. Per farlo, esegui questo comando in una finestra del terminale:
  • $ adb shell cmd appops set <PACKAGE_NAME> RUN_ANY_IN_BACKGROUND deny