O Google tem o compromisso de promover a igualdade racial para as comunidades negras. Saiba como.

Otimizações em segundo plano

Os processos em segundo plano podem consumir muita memória e bateria. Por exemplo, uma transmissão implícita pode iniciar muitos processos em segundo plano que foram registrados para ouvi-la, mesmo que esses processos não tenham tanta utilidade. Isso pode ter um impacto significativo no desempenho do dispositivo e na experiência do usuário.

Para amenizar esse problema, o Android 7.0 (API de nível 24) usa as seguintes restrições:

Se seu app usa qualquer um desses intents, remova as dependências deles assim que possível para segmentar os dispositivos de destino com o Android 7.0 ou versões mais recentes corretamente. O framework do Android oferece várias soluções para reduzir a necessidade dessas transmissões implícitas. Por exemplo, JobScheduler e o novo WorkManager fornecem mecanismos robustos para programar operações de rede quando condições especificadas, como uma conexão com uma rede ilimitada, forem atendidas. Agora também é possível usar JobScheduler para reagir às mudanças nos provedores de conteúdo. Os objetos JobInfo encapsulam os parâmetros que JobScheduler usa para programar seu job. Quando as condições do job forem atendidas, o sistema executará o trabalho no JobService do seu app.

Neste documento, veremos como usar métodos alternativos, como JobScheduler, para adaptar seu app a essas novas restrições.

Restrições iniciadas pelo usuário

A partir do Android 9 (API de nível 28), se um app exibe alguns dos maus comportamentos descritos no Android vitals, o sistema solicita que o usuário restrinja o acesso desse app aos recursos do sistema.

Se o sistema perceber que um app está consumindo recursos em excesso, ele notificará o usuário e dará a opção de restringir as ações do app. Os comportamentos que podem acionar o aviso incluem:

  • Wake locks em excesso: um wake lock parcial mantido por uma hora quando a tela está desativada.
  • Serviços em segundo plano em excesso: o app segmenta níveis de API inferiores a 26 e há excesso de serviços em segundo plano.

As restrições precisas impostas são determinadas pelo fabricante do dispositivo. Por exemplo, em versões do AOSP, os apps restritos não podem executar tarefas, acionar alarmes nem usar a rede, exceto quando o app está no primeiro plano. Para saber os critérios usados para determinar se um app está no primeiro plano, consulte Restrições de serviços em segundo plano. Restrições específicas estão listadas em Restrições de gerenciamento de energia.

Restrições para o recebimento de transmissões de atividade de rede

Os apps para o Android 7.0 (API de nível 24) não recebem transmissões CONNECTIVITY_ACTION quando se registram para recebê-las no manifesto. Processos que dependem dessa transmissão não serão iniciados. Isso pode representar um problema para apps que querem ouvir mudanças de rede ou realizar atividades de rede em massa quando o dispositivo se conecta a uma rede ilimitada. Várias soluções para contornar essa restrição já existem no framework do Android, mas escolher o caminho certo depende do que você quer que o app faça.

Observação: um BroadcastReceiver registrado em Context.registerReceiver() continuará a receber essas transmissões enquanto o app estiver em execução.

Programar jobs de rede em conexões ilimitadas

Ao usar a classe JobInfo.Builder para criar seu objeto JobInfo, aplique o método setRequiredNetworkType() e transmita JobInfo.NETWORK_TYPE_UNMETERED como um parâmetro de trabalho. A amostra de código a seguir programa um serviço para ser executado quando o dispositivo se conectar a uma rede ilimitada enquanto estiver sendo carregado:

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 as condições para o job forem atendidas, o app receberá um callback para executar o método onStartJob() na JobService.class especificada. Para ver mais exemplos de implementação do JobScheduler, consulte o app de amostra JobScheduler.

Uma nova alternativa para o JobScheduler é o WorkManager, uma API que permite programar tarefas em segundo plano que precisam de uma conclusão garantida, independentemente de o processo estar ativo ou não. O WorkManager escolhe a maneira apropriada de executar o trabalho (diretamente em uma linha de execução no processo do app ou usando JobScheduler, FirebaseJobDispatcher ou AlarmManager) com base em fatores como o nível da API do dispositivo. Além disso, o WorkManager não requer o Google Play Services e oferece vários recursos avançados, como encadeamento de tarefas ou verificação do status de uma tarefa. Para saber mais, consulte WorkManager.

Monitorar a conectividade de rede enquanto o app está em execução

Os apps em execução ainda poderão escutar CONNECTIVITY_CHANGE com um BroadcastReceiver registrado. No entanto, a API ConnectivityManager fornece um método mais robusto para solicitar um callback somente quando as condições de rede especificadas são atendidas.

Os objetos NetworkRequest definem os parâmetros do callback de rede em termos de NetworkCapabilities. Você cria objetos NetworkRequest com a classe NetworkRequest.Builder. Em seguida, registerNetworkCallback() transmite o objeto NetworkRequest para o sistema. Quando as condições da rede são atendidas, o app recebe um callback para executar o método onAvailable() definido na classe ConnectivityManager.NetworkCallback.

O app continua recebendo callbacks até o app sair ou chamar unregisterNetworkCallback().

Restrições para o recebimento de transmissões de imagens e vídeos

No Android 7.0 (API de level 24), os apps não podem enviar ou receber transmissões ACTION_NEW_PICTURE ou ACTION_NEW_VIDEO. Essa restrição ajuda a reduzir os impactos no desempenho e na experiência do usuário quando vários apps precisam ser ativados para processar uma nova imagem ou vídeo. O Android 7.0 (API de nível 24) estende JobInfo e JobParameters para fornecer uma solução alternativa.

Acionar jobs em mudanças de URI de conteúdo

Para acionar jobs em mudanças de URI de conteúdo, o Android 7.0 (API de nível 24) estende a API JobInfo com os seguintes métodos:

JobInfo.TriggerContentUri()
Encapsula os parâmetros necessários para acionar um job em mudanças de URI de conteúdo.
JobInfo.Builder.addTriggerContentUri()
Transmite um objeto TriggerContentUri para JobInfo. Um ContentObserver monitora o URI de conteúdo encapsulado. Se houver vários objetos TriggerContentUri associados a um job, o sistema fornecerá um callback mesmo que ele relate uma mudança em apenas um dos URIs de conteúdo.
Adicione a sinalização TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS para acionar o job em caso de mudança em qualquer um dos descendentes do URI especificado. Essa sinalização corresponde ao parâmetro notifyForDescendants transmitido para registerContentObserver().

Observação: TriggerContentUri() não pode ser usado em combinação com setPeriodic() ou setPersisted(). Para monitorar continuamente as alterações de conteúdo, programe um novo JobInfo antes que o JobService do app termine de processar o callback mais recente.

A amostra de código a seguir programa um job a ser acionado quando o sistema informa uma mudança no URI de conteúdo, 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 o sistema indicar uma mudança nos URIs de conteúdo especificados, o app receberá um callback e um objeto JobParameters será transmitido para o método onStartJob() na MediaContentJob.class.

Determinar quais autoridades de conteúdo acionaram um job

O Android 7.0 (API de nível 24) também estende JobParameters para permitir que o app receba informações úteis sobre quais autoridades de conteúdo e URIs acionaram o job:

Uri[] getTriggeredContentUris()
Retorna uma matriz de URIs que acionaram o job. Isso será null se nenhum URI tiver acionado o job (por exemplo, o job foi acionado devido a um prazo ou algum outro motivo) ou se o número de URIs alterados for maior que 50.
String[] getTriggeredContentAuthorities()
Retorna uma matriz de strings de autoridades de conteúdo que acionaram o job. Se a matriz retornada não for null, use getTriggeredContentUris() para recuperar os detalhes sobre quais URIs foram modificados.

A amostra de código a seguir modifica o método JobService.onStartJob() e registra as autoridades de conteúdo e os URIs que acionaram o 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;
    }
    

Otimizar ainda mais seu app

A otimização dos seus apps para serem executados em dispositivos com pouca memória ou em condições de pouca memória pode melhorar o desempenho e a experiência do usuário. A remoção de dependências em serviços em segundo plano e de broadcast receivers implícitos registrados pelo manifesto pode ajudar o app a funcionar melhor nesses dispositivos. Embora o Android 7.0 (API de nível 24) tome medidas para reduzir alguns desses problemas, recomendamos que você otimize seu app para ser executado totalmente sem esses processos em segundo plano.

O Android 7.0 (API de nível 24) introduz alguns outros comandos do Android Debug Bridge (ADB) que podem ser usados para testar o comportamento do app quando esses processos em segundo plano estão desativados:

  • Para simular condições em que transmissões implícitas e serviços em segundo plano estão indisponíveis, digite o seguinte comando:
  •     $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignore
        
  • Para reativar transmissões implícitas e serviços em segundo plano, digite o seguinte comando:
  •     $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow