Junto com recursos e funcionalidades novos, o Android 8.0 traz diversas mudanças de comportamento do sistema e da API. Este documento destaca algumas das principais mudanças que você deve entender e avaliar para os seus aplicativos.
A maioria delas afeta todos os aplicativos direcionados a todas as versões do Android. Porém, muitas das mudanças só afetam aplicativos voltados para o Android 8.0. Para facilitar o entendimento, essa página está dividida em duas seções: Aplicativos voltados para APIs de todos os níveis e Aplicativos voltados para o Android 8.0.
Aplicativos voltados para APIs de todos os níveis
Estas mudanças de comportamento se aplicam a
Limites da execução em segundo plano
Como uma das mudanças que o Android 8.0 introduz para melhorar a eficiência da bateria, quando o aplicativo entra em estado armazenado em cache, sem componentes ativos, o sistema libera todos os wakelocks que o aplicativo tiver.
Além disso, para melhorar o desempenho do dispositivo, o sistema limita alguns comportamentos de aplicativos que não estejam em execução no primeiro plano. Mais especificamente:
- os aplicativos em execução em segundo plano agora têm limites quanto à liberdade de acesso aos serviços de segundo plano.
- Os aplicativos não podem usar o manifesto para se registrar para receber a maioria das transmissões implícitas (ou seja, aquelas que não são direcionadas especificamente para o aplicativo).
Por padrão, essas restrições se aplicam apenas a aplicativos destinados ao O. Entretanto, os usuários podem ativá-las em qualquer aplicativo na tela Configurar, mesmo que o aplicativo não seja destinado ao O.
O Android 8.0 também traz as seguintes mudanças a métodos específicos:
- O método
startService()
agora aciona umaIllegalStateException
se um aplicativo voltado para o Android 8.0 tentar usá-lo em uma situação em que o não é permitido criar serviços de segundo plano. - O novo método
Context.startForegroundService()
inicia um serviço no primeiro plano. O sistema permite que aplicativos chamemContext.startForegroundService()
mesmo que o aplicativo esteja em segundo plano. Entretanto, o aplicativo deve chamar o métodostartForeground()
desse serviço em até cinco segundos após a criação do serviço.
Para saber mais, consulte Limites da execução em segundo plano.
Limites da localização em segundo plano no Android
Para economizar bateria e preservar a experiência do usuário e a integridade do sistema, os aplicativos em segundo plano recebem atualizações de localização com menos frequência quando usados em um dispositivo com Android 8.0. Essa mudança de comportamento afeta todos os aplicativos que recebem atualizações de localização, incluindo o Google Play Services.
Essas mudanças afetam as seguintes APIs:
- Fused Location Provider (FLP)
- Geofencing
- GNSS Measurements
- Location Manager
- Wi-Fi Manager
Para garantir que o aplicativo funcione como o esperado, faça o seguinte:
- Analise a lógica do seu aplicativo e verifique se você está usando as APIs de localização mais recentes.
- Verifique se o aplicativo mostra o comportamento que você espera para cada caso de uso.
- Pense em usar o Fused Location Provider (FLP) ou o Geofencing para lidar com os casos de uso que dependem da localização atual do usuário.
Para saber mais sobre essas mudanças, acesse Limites da localização em segundo plano.
Atalhos de aplicativo
O Android 8.0 introduziu as seguintes alterações nos atalhos de aplicativo:
- A transmissão
com.android.launcher.action.INSTALL_SHORTCUT
não produz mais nenhum efeito no aplicativo, porque agora é implícita e privada. No lugar disso, você deve criar um atalho usando o métodorequestPinShortcut()
da classeShortcutManager
. - A intent
ACTION_CREATE_SHORTCUT
agora pode criar atalhos de teclado, que você gerencia usando a classeShortcutManager
. Essa intent também pode criar atalhos na tela inicial herdados que não interagem comShortcutManager
. Antes, essa intent só podia criar atalhos de inicialização herdados. - Os atalhos criados usando
requestPinShortcut()
e aqueles criados em uma atividade que lida com aACTION_CREATE_SHORTCUT
agora estão totalmente desenvolvidos. Com isso, os aplicativos podem ser atualizados usando os métodos deShortcutManager
. - Atalhos herdados mantêm a funcionalidade das versões anteriores do Android, mas precisam ser convertidos em atalhos de aplicativo manualmente no aplicativo.
Para saber mais sobre as mudanças nos atalhos de aplicativo, leia o guia de recursos da prévia "Como fixar atalhos e widgets".
Localidades e internacionalização
O Android 7.0 (API de nível 24) introduziu o conceito de poder especificar um Locale com categoria padrão, mas algumas APIs continuaram usando o método Locale.getDefault()
genérico, sem argumentos, quando poderiam usar Locale com a categoria DISPLAY
como padrão. No Android 8.0, os métodos a seguir usam Locale.getDefault(Category.DISPLAY)
em vez de Locale.getDefault()
:
Locale.getDisplayScript(Locale)
também retorna para Locale.getDefault()
quando o valor displayScript do argumento Locale
não está disponível.
Veja algumas outras mudanças de localidade de internacionalização abaixo:
- Chamar
Currency.getDisplayName(null)
gera umaNullPointerException
, que é um comportamento igual ao documentado. - A análise do nome do fuso horário mudou. Antes, os dispositivos Android usavam o valor do relógio do sistema em uma amostra em tempo de inicialização para armazenar em cache os nomes de fuso horário usados para analisar horários e data. Assim, a análise podia ser afetada negativamente se o relógio do sistema estivesse incorreto no tempo de inicialização ou em outros casos mais raros.
Agora, em casos comuns, a lógica de análise usa ICU e o valor atual do relógio do sistema para analisar nomes de fuso horário. Essa mudança fornece resultados mais corretos, que podem diferir em versões mais antigas do Android, quando o aplicativo usa classes como
SimpleDateFormat
. - O Android 8.0 atualiza a ICU para a versão 58.
Janelas de alerta
Se o aplicativo usa a permissão SYSTEM_ALERT_WINDOW
e um dos seguintes tipos de janela para tentar exibir alertas sobre outros aplicativos e janelas do sistema:
...essas janelas sempre aparecem sobre as janelas do tipo TYPE_APPLICATION_OVERLAY
. Se o aplicativo é voltado para o Android 8.0, ele usa a janela do tipo TYPE_APPLICATION_OVERLAY
para exibir alertas.
Para saber mais, leia a seção Tipos de janela comuns para alertas nas mudanças de comportamento dos Aplicativos criados para o Android 8.0.
Interação e navegação
Com o advento dos aplicativos Android no Chrome OS e em outros tipos de dispositivo grande, como tablets, estamos vendo um ressurgimento da navegação por teclado nos aplicativos Android. Dentro do Android 8.0, voltamos para o teclado como o dispositivo de interação na navegação, o que cria um modelo previsível e mais confiável de navegação de seta e aba.
Em especial, fizemos as mudanças abaixo no comportamento de foco do elemento:
-
Se você não definiu nenhuma cor para os estados de foco de um objeto
View
(seja um desenhável de primeiro ou segundo plano), a estrutura define uma cor de realce de foco padrão para aView
. O realce de foco é um desenhável com efeito de ondulação baseado no tema da atividade.Se não quiser que um objeto
View
use esse realce padrão quando receber foco, defina o atributoandroid:defaultFocusHighlightEnabled
comofalse
no arquivo XML do layout que contém oView
ou passefalse
parasetDefaultFocusHighlightEnabled()
na lógica da IU do seu aplicativo. - Para testar a forma com que a interação pelo teclado afeta o foco no elemento da IU, ative a opção ao desenvolvedor Drawing > Show layout bounds. No Android 8.0, essa opção exibe um ícone "X" sobre o elemento que está em foco no momento.
Além disso, todos os elementos da barra de ferramentas do Android 8.0 são clusters de navegação por teclado automáticos, o que facilita entrar e sair da navegação de cada barra de ferramenta como um todo.
Para saber mais sobre como melhorar o suporte a navegação por teclado do seu aplicativo, leia o guia Compatibilidade com navegação por teclado.
Preenchimento automático de formulários Web
Agora que a estrutura de preenchimento automático do Android 8.0ferece suporte integrado ao recurso de preenchimento automático, os métodos a seguir relacionados a objetos WebView
foram alterados para aplicativos instalados em dispositivos com o Android 8.0:
WebSettings
-
- O método
getSaveFormData()
agora retornafalse
. Anteriormente, esse método retornavatrue
. - Chamar
setSaveFormData()
não produz mais nenhum efeito.
- O método
WebViewDatabase
-
- Chamar
clearFormData()
não produz mais nenhum efeito. - O método
hasFormData()
agora retornafalse
. Anteriormente, esse método retornavatrue
quando o formulário continha dados.
- Chamar
Acessibilidade
Os serviços de acessibilidade agora conhecem todas as instâncias de ClickableSpan
dentro dos objetos TextView
do seu aplicativo.
Saiba mais sobre como tornar o aplicativo mais acessível consultando Acessibilidade.
Redes e conectividade HTTP(S)
O Android 8.0 apresenta as mudanças de comportamento a seguir em redes e conectividade HTTP(S):
- As solicitações OPTIONS sem "body" têm um cabeçalho
Content-Length: 0
. Antigamente, elas não tinham cabeçalhoContent-Length
. - HttpURLConnection normaliza URLs que contêm caminhos vazios anexando uma barra após o nome do host ou da autoridade. Por exemplo,
http://example.com
é convertido emhttp://example.com/
. - Um seletor de proxy personalizado configurado por ProxySelector.setDefault() só visa o endereço (esquema, host e porta) do URL solicitado. Com isso, a seleção de proxy pode se basear apenas nesses valores. Um URL passado a um seletor de proxy personalizado não inclui o caminho, os parâmetros de consulta nem os fragmentos do URL solicitado.
- OS URIs não podem conter rótulos vazios.
Nas versões anteriores, a plataforma possibilitava uma alternativa de aceitar rótulos vazios em nomes de host, o que é um uso ilegal dos URIs. Essa alternativa buscava oferecer compatibilidade com versões mais antigas do libcore. Os desenvolvedores que usam a API incorretamente verão uma mensagem do ADB: "URI example.com tem rótulos vazios no nome do host. Isso está incorreto e não será aceito em versões futuras do Android." No Android 8.0, essa alternativa não existe: o sistema retorna nulo para URIs de composição incorreta.
- A implementação de HttpsURLConnection do Android 8.0 não retrocede a versão do protocolo TLS/SSL sem segurança.
- O gerenciamento de conexões HTTP(S) encapsuladas mudou da seguinte forma:
- Ao encapsular conexão sobre conexão HTTPS, o sistema coloca o número da porta (:433) corretamente na linha do Host quando envia essa informação a um servidor intermediário. Antigamente, o número da porta só aparecia na linha CONNECT.
- O sistema não envia mais cabeçalhos "user-agent" e "proxy-authorization" por uma solicitação encapsulada ao servidor proxy.
O sistema não envia mais um cabeçalho "proxy-authorization" em uma Http(s)URLConnection encapsulada ao proxy ao estabelecer o túnel. Em vez disso, o sistema gera um cabeçalho "proxy-authorization" e envia-o ao proxy quando esse proxy envia HTTP 407 em resposta à solicitação inicial.
Com o mesmo raciocínio, o sistema deixou de copiar a cabeçalho "user-agent" da solicitação encapsulada para a solicitação de proxy que estabelece o túnel. Agora, a biblioteca gera um cabeçalho "user-agent" para essa solicitação.
- O método
send(java.net.DatagramPacket)
gerará uma SocketException se o método connect() executado antes falhar.- DatagramSocket.connect() acionará uma DatagramSocket.connect() se houver erro interno. Antes do Android 8.0, uma chamada de recv() subsequente gerava uma SocketException, mesmo que houvesse uma chamada de send() bem-sucedida. Para dar mais consistência, ambas as chamadas agora geram uma SocketException.
- InetAddress.isReachable() tenta o ICMP antes de retornar ao protocolo TCP de eco.
- Alguns host que bloqueiam a porta 7 (eco de TCP), como o google.com, agora são acessíveis se aceitarem o protocolo ICMP de eco.
- Quanto aos hosts realmente inacessíveis, essa mudança exige duas vezes mais tempo para receber retornos da chamada.
Bluetooth
O Android 8.0 promove as seguintes mudanças no comprimento dos dados que o método ScanRecord.getBytes()
busca:
- O método
getBytes()
não presume o número de bytes recebidos. Portanto, os aplicativos não devem precisar de nenhum número máximo ou mínimo de bytes retornados. Em vez disso, eles devem avaliar o comprimento da matriz resultante. - Dispositivos compatíveis com Bluetooth 5 podem retornar comprimento de dado que exceda o valor máximo anterior de cerca de 60 bytes.
- Se um dispositivo remoto não fornecer uma resposta analisada, é possível que se retorne menos de 60 bytes.
Conectividade uniforme
O Android 8.0 faz diversas melhorias nas Configurações de Wi-Fi para facilitar a escolha de uma rede Wi-Fi que ofereça a melhor experiência do usuário. Mudanças específicas incluem:
- Melhorias de estabilidade e confiabilidade.
- Uma IU de leitura mais intuitiva.
- Um só menu consolidado de preferências de Wi-Fi.
- Em dispositivos compatíveis, ativação automática no Wi-Fi quando uma rede salva de alta qualidade estiver próxima.
Segurança
O Android 8.0 apresenta as seguintes mudanças em relação a segurança:
- A plataforma não oferece mais suporte a SSLv3.
- Ao estabelecer uma conexão HTTPS com um servidor que implementa a negociação de versão do protocolo TLS,
HttpsURLConnection
não recorre mais à alternativa de retroceder a versões antigas do protocolo e tentar novamente. - O Android 8.0 aplica um filtro de computação segura (SECCOMP, na sigla em inglês) a todos os aplicativos. A lista de chamadas do sistema permitidas é restrita às expostas por Bionic. Embora haja diversas outras chamadas do sistema para a retrocompatibilidade, não recomendamos usá-las.
- Os objetos
WebView
do seu aplicativo agora funcionam em modo multiprocesso. O conteúdo Web é tratado em um processo isolado do processo que contém o aplicativo, aumentando a segurança. -
Não é mais possível presumir que os APKs estão dentro de diretórios cujos nomes se encerram em -1 ou -2. Os aplicativos devem usar
sourceDir
para encontrar o diretório, e não confiar no formato do diretório diretamente. - Para saber mais sobre as melhorias de segurança relacionadas ao uso de bibliotecas nativas, acesse Bibliotecas nativas.
Se precisar de mais instruções sobre como tornar o seu aplicativo mais seguro, acesse Segurança para o desenvolvedor Android.
Privacidade
O Android 8.0 também conta com mudanças de privacidade na plataforma. Elas são as seguintes:
- Agora, a plataforma gerencia identificadores de forma diferente.
-
Para aplicativos que foram instalados antes de um OTA para uma versão do Android 8.0 (nível de API 26), o valor de
ANDROID_ID
permanece o mesmo a não ser que eles sejam desinstalados e reinstalados após a OTA. Para preservar os valores entre desinstalações após o OTA, os desenvolvedores podem associar os valores novos e antigos usando o backup de chave/valor. - Para aplicativos instalados em um dispositivo com o Android 8.0, o valor de
ANDROID_ID
agora recebe escopo por aplicativo que assina a chave, além de por usuário. O valor deANDROID_ID
é exclusivo de cada combinação de chave de assinatura de aplicativo, usuário e dispositivo. Como resultado, aplicativos com diferentes chaves de assinatura executados no mesmo dispositivo não veem mais o mesmo Android ID (inclusive para o mesmo usuário). - O valor de
ANDROID_ID
não é alterado após a desinstalação ou reinstalação do pacote, desde que a chave de assinatura seja a mesma (e que o aplicativo não tenha sido instalado antes de um OTA para uma versão do O). - O valor de
ANDROID_ID
não é alterado mesmo que uma atualização do sistema faça com que a chave de assinatura de pacote mude.
Se precisar um sistema padronizado e simples para monetizar aplicativos, use o ID de publicidade. O ID de publicidade é um ID exclusivo que pode ser reconfigurado pelo usuário voltado para publicidade e fornecido pelo Google Play Services.
-
Para aplicativos que foram instalados antes de um OTA para uma versão do Android 8.0 (nível de API 26), o valor de
net.hostname
do sistema gera um resultado nulo.Registro de exceções não capturadas
Se um aplicativo instala Thread.UncaughtExceptionHandler
que não faz chamadas pelo Thread.UncaughtExceptionHandler
padrão, o sistema não encerra o aplicativo quando ocorre uma exceção não capturada. A partir do Android 8.0, nessa situação, o sistema registra a movimentação de pilha da exceção. Nas versões anteriores da plataforma, o sistema não teria registrado essa movimentação.
Recomendamos que as implementações de Thread.UncaughtExceptionHandler
personalizadas sempre façam chamadas pelo gerenciador padrão. Os aplicativos que seguirem essa recomendação não serão afetados pelas mudanças do Android 8.0.
Mudança de estado de uso do provedor de contatos
Nas versões anteriores do Android, o componente Contacts Provider permitia que os desenvolvedores obtivessem os dados de uso de cada contato. Esses dados fornecem informações de cada endereço de e-mail e número de telefone associado a determinado contato, incluindo o número de vezes que se estabeleceu contato com ele e a última vez que se realizou um contato. Os aplicativos que solicitam a permissão READ_CONTACTS
podem ler esses dados.
Os aplicativos ainda podem ler esses dados se solicitarem a permissão READ_CONTACTS
. A partir do Android 8.0, as consultas de dados de uso retornam números aproximados, não valores exatos. O sistema do Android mantém os valores exatos internamente, então essa mudança não afeta a API de preenchimento automático.
Essa mudança de comportamento afeta os seguintes parâmetros de consulta:
Gerenciamento de coleta
Agora, AbstractCollection.removeAll()
e AbstractCollection.retainAll()
sempre geram uma NullPointerException
(antes, a NullPointerException
não era acionada quando a coleta estava vazia). Essa mudança deixa o comportamento mais coerente com a documentação.
Android empresarial
O Android 8.0 muda o comportamento de algumas APIs e recursos para aplicativos empresariais, incluindo os controladores de política do dispositivo (DPCs). As mudanças incluem:
- Novos comportamentos para ajudar os aplicativos a dar suporte a perfis de trabalho em dispositivos totalmente gerenciados.
- Mudanças ao gerenciamento de atualizações do sistema, à verificação de aplicativos e à autenticação para aumentar a integridade do sistema e do dispositivo.
- Melhorias à experiência do usuário para provisionamento, notificações, a tela "Recentes" e VPN sempre ativa.
Para ver todas as mudanças empresariais no Android 8.0 e entender como elas podem afetar o seu aplicativo, leia Android no Enterprise.
Aplicativos voltados para o Android 8.0
Estas mudanças de comportamento afetam exclusivamente os aplicativos voltados para a plataforma O ou posterior. Aplicativos compilados no Android 8.0 ou em posterior ou com targetSdkVersion
definida para o Android 8.0 ou posterior devem ser adaptados para oferecer suporte adequado aos comportamentos sempre que aplicável.
Janelas de alerta
Os aplicativos que usam a permissão SYSTEM_ALERT_WINDOW
não podem mais usar os tipos de janela abaixo para exibir alertas sobre outros aplicativos e janelas do sistema:
Agora, os aplicativos têm que usar um novo tipo de janela chamado TYPE_APPLICATION_OVERLAY
.
Ao usar a janela TYPE_APPLICATION_OVERLAY
para exibir alertas no aplicativo, é importante ter em mente estas características do novo tipo de janela:
- As janelas de alerta de um aplicativo sempre aparecem embaixo das janelas críticas do sistema, como a barra de status e editores de método de entrada.
- O sistema pode mover ou redimensionar janelas
TYPE_APPLICATION_OVERLAY
para melhorar a apresentação na tela. - Ao abrir a aba de notificações, os usuários podem acessar as configurações para impedir que o aplicativo exiba janelas de alerta
TYPE_APPLICATION_OVERLAY
.
Notificações de alteração de conteúdo
O Android 8.0 altera o comportamento de ContentResolver.notifyChange()
e registerContentObserver(Uri, boolean, ContentObserver)
em aplicativos destinados ao Android 8.0.
Essas APIs agora exigem que um ContentProvider
válido seja definido para a autoridade em todos os URIs. Definir um ContentProvider
válido com permissões importantes ajuda você a defender o seu aplicativo contra alterações de conteúdo por parte de aplicativos maliciosos e evita o possível vazamento de dados privados.
Foco de visualização
Objetos View
clicáveis agora também podem ser focados por padrão. Se quiser que um objeto View
seja clicável mas não possa receber foco, defina o atributo android:focusable
como false
no arquivo XML do layout que contém o View
ou passe false
para setFocusable()
na lógica da IU do seu aplicativo.
Segurança
Se a configuração de segurança de rede do seu aplicativo recusar suporte a tráfego de texto não criptografado, os objetos WebView
do aplicativo não poderão acessar sites por HTTP. Por isso, todos os objetos WebView
devem usar HTTPS.
Se precisar de mais instruções sobre como tornar o seu aplicativo mais seguro, acesse Segurança para o desenvolvedor Android.
Detectabilidade e acesso a contas
Os aplicativos não podem mais acessar contas de usuário, a menos que o autenticador possua as contas ou o usuário autorize o acesso. A permissão GET_ACCOUNTS
não é mais suficiente. Para conseguir acesso a uma conta, os aplicativos devem usar AccountManager.newChooseAccountIntent()
ou um método específico do autenticador. Depois de obter o acesso a contas, o aplicativo pode chamar AccountManager.getAccounts()
para efetivamente acessá-las.
O Android 8.0 suspendeu o uso de LOGIN_ACCOUNTS_CHANGED_ACTION
. Agora, os aplicativos devem usar addOnAccountsUpdatedListener()
para receber atualizações de contas em tempo de execução.
Para obter mais informações sobre novas APIs e métodos adicionados para a detectabilidade e o acesso a contas, acesse Detectabilidade e acesso a contas na seção "Novas APIs" deste documento.
Privacidade
As mudanças a seguir afetam a privacidade no Android 8.0.
-
As propriedades
net.dns1
,net.dns2
,net.dns3
enet.dns4
do sistema não estão mais disponíveis, o que aumenta a privacidade da plataforma. -
Para encontrar informações de rede, como servidores DNS, os aplicativos com a permissão
ACCESS_NETWORK_STATE
podem registrar um objetoNetworkRequest
ouNetworkCallback
. Essas classes estão disponíveis no Android 5.0 (API de nível 21) e em versões posteriores. -
Build.SERIAL está obsoleta. Com isso, os aplicativos que precisam saber o número de série do equipamento devem usar o novo método
Build.getSerial()
, que exige a permissãoREAD_PHONE_STATE
. -
A
LauncherApps
API não permite mais que aplicativos de perfis de trabalho coletem informações sobre o perfil principal. Quando o usuário está em um perfil de trabalho, aLauncherApps
API age como se não houvesse aplicativos instalados em outros perfis dentro do mesmo grupo de perfis. Como antes, tentar acessar perfis não relacionados gera SecurityExceptions.
Permissões
Antes do Android 8.0, se o aplicativo solicitasse permissão em tempo de execução e ela fosse concedida, o sistema também concederia (incorretamente) ao aplicativo as demais permissões que pertencessem ao mesmo grupo de permissões e que tivessem sido registradas no manifesto.
Para aplicativos voltados para o Android 8.0, esse comportamento foi corrigido. O aplicativo só recebe as permissões que foram explicitamente solicitadas. Porém, quando o usuário concede uma permissão ao aplicativo, todas as permissões posteriormente solicitadas àquele grupo de permissões são concedidas automaticamente.
Por exemplo, suponha que um aplicativo liste READ_EXTERNAL_STORAGE
e WRITE_EXTERNAL_STORAGE
no manifesto. O aplicativo solicita READ_EXTERNAL_STORAGE
e o usuário a concede. Se o aplicativo trabalha com API de nível 24 ou anterior, o sistema também concede WRITE_EXTERNAL_STORAGE
ao mesmo tempo, porque ela pertence ao mesmo grupo de permissões STORAGE
e está registrada no manifesto. Se o aplicativo trabalha com o Android 8.0, o sistema só concede READ_EXTERNAL_STORAGE
em um primeiro momento. Porém, se o aplicativo solicitar WRITE_EXTERNAL_STORAGE
mais tarde, o sistema concede imediatamente esse privilégio sem consultar o usuário.
Mídia
- A estrutura realiza atenuação automática de áudio. Os aplicativos não perdem o foco no caso de
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
. Novas APIs estão disponíveis para aplicativos que precisam pausar em vez de atenuar. Observe que esse comportamento não é implementado na versão 1 do Android 8.0. - Quando o usuário aceita uma chamada telefônica, os fluxos de mídia ativos param pelo tempo de duração da chamada.
- Todas as APIs relacionadas ao áudio devem usar
AudioAttributes
em vez de tipos de stream de áudio para descrever o caso de uso de reprodução de áudio. Continue a usar tipos de stream de áudio somente para controles de volume. Outros usos de tipos de stream (por exemplo, oAudioTrack constructor
obsoleto) ainda funcionam, mas o sistema registra isso como um erro. - Ao usar uma
AudioTrack
, se o aplicativo solicitar um buffer de áudio grande o suficiente, a estrutura tentará usar a saída do buffer grande, se estiver disponível. - No Android 8.0, o processamento de eventos de botão de mídia é diferente:
- O processamento de botões de mídia em uma atividade de IU não mudou: atividades de primeiro plano ainda têm prioridade no processamento de botões de mídia.
- Se a atividade de primeiro plano não processar o botão de mídia, o sistema roteia os botões de mídia para o aplicativo que reproduziu áudio localmente por último. O status de ativo, os sinalizadores e o estado de reprodução de uma sessão de mídia não são mais considerados ao determinar qual aplicativo deve receber os eventos de botão de mídia. Sessões de mídia podem receber eventos de botão de mídia mesmo depois que o aplicativo chamar setActive(false).
- Se a sessão de mídia do aplicativo for liberada, o sistema enviará o evento de botão de mídia para o MediaButtonReceiver do aplicativo, caso ele tenha um.
- Para todos os demais casos de uso, o sistema descarta o evento de botão de mídia. É melhor não reproduzir do que iniciar o aplicativo errado.
A nova lógica de roteamento de botões de mídia está resumida no diagrama a seguir:
Bibliotecas nativas
Nos aplicativos voltados para o Android 8.0, as bibliotecas nativas não são mais carregadas se contiverem algum segmento para carregar que seja gravável e executável ao mesmo tempo. Alguns aplicativos podem parar de funcionar por causa dessa mudança se tiverem bibliotecas nativas com segmentos incorretos. Essa é uma medida de aumento de segurança.
Para saber mais, leia Segmentos graváveis e executáveis.
Como com versões anteriores da prévia ao desenvolvedor, o Android 8.0 também torna todos os problemas relacionados ao vinculador mais visíveis. As mudanças no vinculador são ligadas ao nível da API com que o aplicativo visa a trabalhar. Se houver uma mudança no vinculador da API almejada, o aplicativo não conseguirá carregar a biblioteca. Se você busca trabalhar com uma API de nível inferior ao da API que apresenta a mudança no vinculador, o logcat exibirá uma advertência. Durante uma prévia, problemas relacionados a vinculadores não só aparecem no logcat, mas também como uma notificação. Essa mudança aumenta a visibilidade dos problemas antes do nível da API em que a advertência se torna um erro.
Gerenciamento de coleta
No Android 8.0, Collections.sort()
é implementada com base em List.sort()
. A recíproca é verdadeira no Android 7.x (APIs de nível 24 e 25): A implementação padrão de List.sort()
chamava Collections.sort()
.
Essa mudança permitiu que Collections.sort()
tirasse vantagem de implementações otimizadas de List.sort()
, mas com as seguintes limitações:
As implementações de
List.sort()
não podem chamarCollections.sort()
, porque isso geraria recursão infinita e, por consequência, fluxo excessivo na pilha. Em vez disso, se você quiser que a sua implementação deList
tenha o comportamento padrão, evite neutralizarsort()
.Se uma classe primária implementar
sort()
de forma incorreta, normalmente não haverá problema para neutralizarList.sort()
com uma implementação criada com base emList.toArray()
,Arrays.sort()
eListIterator.set()
. Por exemplo:@Override public void sort(Comparator<? super E> c) { Object[] elements = toArray(); Arrays.sort(elements, c); ListIterator<E> iterator = (ListIterator<Object>) listIterator(); for (Object element : elements) { iterator.next(); iterator.set((E) element); } }
Na maioria dos casos, é possível neutralizar
List.sort()
com uma implementação que delega a outras implementações padrão, dependendo do nível da API. Por exemplo:@Override public void sort(Comparator<? super E> comparator) { if (Build.VERSION.SDK_INT <= 25) { Collections.sort(this); } else { super.sort(comparator); } }
Se você estiver fazendo esse último caso só porque quer disponibilizar um método
sort()
nas APIs de todos os níveis, pense em dar a ele um nome exclusivo, comosortCompat()
, em vez de neutralizarsort()
.-
Agora,
Collections.sort()
é considerado uma modificação estrutural em implementações de List que chamamsort()
. Por exemplo, em versões da plataforma anteriores ao Android 8.0, iterar em umaArrayList
e chamarsort()
nela parcialmente por meio da iteração geraria umaConcurrentModificationException
se a ordenação fosse feita comList.sort()
.Collections.sort()
não acionava uma exceção.Essa mudança faz a plataforma se comportar de forma mais consistente: ambas as abordagens agora geram uma
ConcurrentModificationException
.
Comportamento de carregamento de classe
O Android 8.0 faz análises para confirmar que os carregadores de classe não rompam as premissas do tempo de execução quando carregam novas classes. Essas análises são realizadas mesmo que a classe esteja referenciada em Java (em forName()
), bytecode do Dalvik ou JNI. A plataforma não intercepta chamadas diretas do Java para o método loadClass()
nem analisa os resultados dessas chamadas. Esse comportamento não deve afetar o funcionamento dos carregadores de classe que estão operando bem.
A plataforma analisa se o descritor da classe que o carregador de classe retorna é o descritor esperado. Se não for, a plataforma aciona o erro NoClassDefFoundError
e armazena uma mensagem detalhada na exceção, indicando a discrepância.
A plataforma também analisa se os descritores das classes solicitadas são válidos. Essa análise capta as chamadas de JNI que carregam indiretamente classes como GetFieldID()
e passam descritores inválidos a elas. Por exemplo, um campo com a assinatura java/lang/String
não é encontrado porque essa assinatura é inválida — ela deveria ser Ljava/lang/String;
.
Esse é um caso diferente de uma chamada de JNI a FindClass()
, em que java/lang/String
é um nome totalmente qualificado válido.
O Android 8.0 não oferece suporte a diversos carregadores de classes tentando definir classes usando o mesmo objeto DexFile ao mesmo tempo. Tentar fazer isso faz o tempo de execução do Android acionar o erro InternalError
com a seguinte mensagem: "Tentativa de registrar <filename>
do arquivo dex com diversos carregadores de classe".
A DexFile API foi suspensa e, para substituí-la, recomendamos usar um dos carregadores de classe da plataforma, incluindo PathClassLoader
ou BaseDexClassLoader
.
Observação: você pode criar diversos carregadores de classe que referenciam o mesmo contêiner de arquivos APK ou JAR do sistema de arquivos. Normalmente, fazer isso não gera muita sobrecarga de memória: se os arquivos DEX do contêiner forem armazenados em vez de comprimidos, a plataforma poderá realizar uma operação de mmap
neles em vez de extraí-los diretamente. Porém, se a plataforma precisa extrair o arquivo DEX do contêiner, referenciar o arquivo dessa maneira pode consumir muita memória.
No Android, todos os carregadores de classe são considerados passíveis de paralelismo. Quando vários encadeamentos competem para carregar a mesma classe com o mesmo carregador de classe, o primeiro encadeamento a concluir a operação vence, e o resultado é usado nos outros encadeamentos. Esse comportamento ocorre em qualquer cenário — se o carregador de classe retornou a mesma classe, retornou uma classe diferente ou acionou uma exceção. A plataforma ignora essas exceções silenciosamente.
Atenção: nas versões da plataforma anteriores ao Android 8.0, quebrar essas premissas pode fazer a mesma classe ser definida diversas vezes, corromper a pilha por conta de confusão de classes e produzir outros efeitos indesejados.