Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

Cambios de comportamiento en Android 8.0

Además de nuevas funciones y capacidades, Android 8.0 incorpora varios cambios en el comportamiento del sistema y de la API. En este documento, se destacan algunos de los cambios claves que debes comprender y contemplar en tus apps.

La mayoría de estos cambios tienen efecto en todas las apps, sin importar la versión de Android que tengan como objetivo. Sin embargo, varios cambios solo afectan a las aplicaciones orientadas a Android 8.0. Para brindar una mayor claridad, esta página se divide en dos secciones: aplicaciones orientadas a todos los niveles de API y aplicaciones orientadas a Android 8.0.

Aplicaciones orientadas a todos los niveles de API

Estos cambios de comportamientos se aplican a todas las aplicaciones cuando se ejecutan en la plataforma de Android 8.0, independientemente del nivel de API al que se orienten. Todos los desarrollares deben revisar estos cambios y modificar sus aplicaciones para admitirlos de manera correspondiente, cuando se puedan aplicar a la aplicación.

Límites de ejecución en segundo plano

Uno de los cambios que Android 8.0 presenta para aumentar la duración de la batería consiste en que, cuando tu app ingresa en el estado de almacenamiento en caché sin componentes activos, el sistema libera las funciones wakelock de ella.

Además, para mejorar el rendimiento del dispositivo, el sistema limita ciertos comportamientos de las apps que no se ejecutan en primer plano. En particular:

  • Ahora, las aplicaciones que se ejecutan en segundo plano tienen límites sobre el nivel de libertad de acceso a los servicios en segundo plano que tienen.
  • Las apps no pueden usar sus manifiestos para registrarse en la mayoría de las transmisiones implícitas (esto es, transmisiones que no están orientadas específicamente a la app).

De forma predeterminada, estas restricciones solo se aplican a apps orientadas a O. Sin embargo, los usuarios pueden habilitarlas para cualquier app desde la pantalla de Configuración aunque no esté orientada a O.

En Android 8.0 también se incluyen los siguientes cambios en métodos específicos:

  • El método startService() ahora genera una IllegalStateException si una app para Android 8.0 intenta usar ese método en una situación en la que no esté permitido crear servicios en segundo plano.
  • El nuevo método Context.startForegroundService() inicia un servicio en primer plano. El sistema permite que las apps llamen a Context.startForegroundService() incluso mientras la app esté en segundo plano. Sin embargo, la app debe llamar al método startForeground() del servicio en un plazo de hasta cinco segundos después de que se cree el servicio.

Para obtener más información, consulta Límites de ejecución en segundo plano.

Limites de ubicación en segundo plano de Android

Para preservar la batería, la experiencia del usuario y el funcionamiento correcto del sistema, las apps en segundo plano reciben actualizaciones de ubicación con menor frecuencia cuando se usan en un dispositivo con Android 8.0. Este cambio de comportamiento afecta a todas las apps que reciben actualizaciones de ubicación, incluidos los servicios de Google Play.

Estos cambios afectan las siguientes API:

  • Proveedor de ubicación combinada (FLP)
  • Geofencing
  • GNSS Measurements
  • Location Manager
  • Wi-Fi Manager

Para asegurarte de que tu app se ejecute de la forma prevista, completa los siguientes pasos:

  • Revisa la lógica de tu aplicación y asegúrate de usar la API de ubicación más reciente.
  • Verifica, mediante una prueba, que tu aplicación exhiba el comportamiento que esperas para cada caso de uso.
  • Considera recurrir al proveedor de ubicación combinada (FLP) o al perimetraje para manejar los casos de uso que dependan de la ubicación actual del usuario.

Para obtener más información sobre estos cambios, consulta Límites de ubicación en segundo plano.

Combinaciones de teclas para apps

En Android 8.0 se incluyen los siguientes cambios en combinaciones de teclas para apps:

  • La transmisión com.android.launcher.action.INSTALL_SHORTCUT ya no tiene ningún efecto en tu aplicación, porque ahora es una transmisión implícita privada. Ahora debes crear una combinación de teclas para una aplicación usando el método requestPinShortcut() desde la clase ShortcutManager.
  • La intent ACTION_CREATE_SHORTCUT ahora puede crear combinaciones de teclas para aplicaciones que podrás administrar usando la clase ShortcutManager. Esta intent también puede crear combinaciones de teclas de lanzadores heredados que no interactúan con ShortcutManager. Anteriormente, esta intent solo podía crear combinaciones de teclas de lanzadores heredados.
  • Las combinaciones de teclas creadas con requestPinShortcut() y las combinaciones de teclas creadas en una actividad que maneja la intent ACTION_CREATE_SHORTCUT ahora son combinaciones de teclas completamente desarrolladas. Como un resultado, ahora las aplicaciones pueden actualizarlas usando los métodos en ShortcutManager.
  • Las combinaciones de teclas heredadas mantienen la funcionalidad de versiones anteriores de Android, pero debes convertirlas a combinaciones de teclas para apps manualmente en tu app.

Para obtener información sobre los cambios en combinaciones de teclas de apps, consulta la guía Funciones Fijación de combinaciones de teclas y Widgets de la Preview.

Configuración regional e internacionalización

En Android 7.0 (nivel de API 24) se presentó el concepto de la capacidad de especificación de una configuración regional de categoría predeterminada, pero en algunas API se continuó usando el método genérico Locale.getDefault() sin argumentos cuando debió usarse la configuración regional de categoría DISPLAY predeterminada. En Android 8.0, ahora los siguientes métodos usan Locale.getDefault(Category.DISPLAY) en lugar de Locale.getDefault():

Locale.getDisplayScript(Locale) también regresa a Locale.getDefault() cuando el valor de displayScript especificado para el argumento de Locale no está disponible.

A continuación, se mencionan los cambios adicionales relacionados con la configuración regional y la internacionalización:

  • Las llamadas a Currency.getDisplayName(null) generan una NullPointerException, conforme al comportamiento documentado.
  • El análisis nombres de zonas horarias ha cambiado. Anteriormente, los dispositivos Android usaban el valor del reloj del sistema tomado en el momento del inicio a fin de almacenar en caché los nombres de zonas horarias usados para analizar la fecha y la hora. Como resultado, el análisis podía experimentar efectos negativos si el reloj del sistema no funcionaba bien en el momento del inicio o en otros casos poco comunes.

    Ahora, en casos comunes la lógica de análisis usa ICU y el valor actual del reloj del sistema al analizar los nombres de las zonas horarias. Este cambio ofrece resultados más correctos, que pueden ser diferentes en versiones anteriores de Android, cuando tu aplicación usa clases como SimpleDateFormat.

  • Android 8.0 actualiza ICU a la versión 58.

Ventanas de alerta

Si una app usa el permiso SYSTEM_ALERT_WINDOW y uno de los siguientes tipos de ventana para intentar mostrar ventanas de alerta sobre otras apps y ventanas del sistema:

... estas ventanas siempre aparecen debajo de las ventanas que usan el tipo de ventana TYPE_APPLICATION_OVERLAY. Si una app está orientada a Android 8.0, esta usa el tipo de ventana TYPE_APPLICATION_OVERLAY para mostrar ventanas de alerta.

Para obtener más información, consulta la sección Tipos comunes de ventanas para ventanas de alerta en los cambios de comportamiento de Aplicaciones orientadas a Android 8.0.

Entrada y navegación

Con la aparición de las apps de Android en el sistema operativo Chrome y otros factores de forma importantes, como las tablets, podemos ver un resurgimiento del uso de la navegación por teclado dentro de las apps de Android. En Android 8.0, hemos vuelto a tratar el uso del teclado como dispositivo de entrada de navegación, lo cual da como resultado un modelo más confiable y predecible para una navegación basada en flechas y pestañas.

En particular, hemos realizado los siguientes cambios en el comportamiento del foco de elementos:

  • Si no has definido ningún color de estado de foco para un objeto View (su elemento de diseño en primero o segundo plano), el marco de trabajo ahora configurará un color de resalte de foco predeterminado para la View. Este resalte de foco es un elemento de diseño de efecto de ondas que se basa en el tema de la actividad.

    Si no deseas un objeto View para usar este resalte predeterminado cuando recibe foco, fija el atributo android:defaultFocusHighlightEnabled en false en el archivo XML de diseño que contiene la View, o pasa false a setDefaultFocusHighlightEnabled() en la lógica de IU de tu app.

  • Para probar la forma en que la entrada de tu teclado afecta el foco de elementos de IU, puedes habilitar la opción del desarrollador Drawing > Show layout bounds. En Android 8.0, esta opción muestra un ícono “X” en el elemento que actualmente tiene foco.

A su vez, todos los elementos de la barra de herramientas en Android 8.0 son automáticamente clústeres de navegación por teclado, lo cual hace más sencilla la navegación para los usuarios hacia adentro y afuera de cada barra de herramientas en general.

Para obtener información sobre cómo mejorar la compatibilidad con la navegación con teclado dentro de tu app, lee la guía Compatibilidad con la navegación por teclado.

Autocompletado de formularios web

Ahora que el marco de trabajo Autofill de Android proporciona asistencia integrada para la funcionabilidad de autocompletado, los siguientes métodos relacionados con los objetos WebView han cambiado para las apps instaladas en dispositivos con Android 8.0:

WebSettings
WebViewDatabase
  • Llamar a clearFormData() ya no tiene efecto.
  • Ahora, el método hasFormData() muestra false. Anteriormente, este método mostraba true cuando el formulario contenía datos.

Accesibilidad

Los servicios de accesibilidad ahora reconocen todas las instancias de ClickableSpan dentro de los objetos TextView de tu app.

Para obtener más información sobre cómo hacer que tu app sea más accesible, consulta Accesibilidad.

Conectividad de red y HTTP(S)

En Android 8.0, se incluyen los siguientes cambios de comportamiento respecto de la conectividad de redes y HTTP(S):

  • Las solicitudes de OPTIONS sin cuerpo tienen un encabezado Content-Length: 0. Anteriormente, no tenían un encabezado Content-Length.
  • HttpURLConnection normaliza URL que contienen rutas de acceso vacías añadiendo una barra diagonal después del nombre de host o autoridad. Por ejemplo, convierte http://example.com en http://example.com/.
  • Un selector proxy personalizado a través de ProxySelector.setDefault() solo tiene como objetivo la dirección (esquemas, host y puerto) de una URL solicitada. Como resultado, es posible que la selección se proxy se base únicamente en estos valores. Una URL que se pasa a un selector proxy personalizado no incluye la ruta de acceso, parámetros de consulta ni fragmentos de la URL solicitada.
  • Los URI no pueden contener etiquetas.

    Anteriormente, la plataforma era compatible con el método alternativo de aceptar etiquetas vacías en nombres de host, lo cual representa un uso no permitido de los URI. Este método alternativo era para fines de compatibilidad con lanzamientos anteriores de libcore. Los desarrolladores que usaban la API de manera incorrecta veían el siguiente mensaje de ADB: "URI example..com has empty labels in the hostname. This is malformed and will not be accepted in future Android releases” (el URI example..com tiene etiquetas vacías en el nombre de host, el formato es incorrecto y no se aceptará en futuras versiones de Android). En Android 8.0 se elimina este método alternativo; el sistema muestra null para URI formadas incorrectamente.

  • La implementación que Android 8.0 hace de HttpsURLConnection no realiza cambios inseguros a versiones anteriores de protocolo TLS/SSL.
  • El control de tunelización de conexiones HTTP(S) presenta los siguientes cambios:
    • Cuando se realiza la tunelización de conexiones HTTPS sobre la conexión, el sistema dispone correctamente el número de puerto (:443) en la línea de host al enviarse esta información a un servidor intermedio. Anteriormente, el número de puerto solo existía en la línea CONNECT.
    • El sistema ya no envía encabezados de usuario-agente ni de autorización de proxy de una solicitud tunelizada al servidor proxy.

      El sistema ya no envía un título de autorización proxy en una Http(s)URLConnection tunelizada al proxy cuando se configura el túnel. Ahora, el sistema genera un título de autorización de proxy y lo envía al proxy cuando este envía HTTP 407 en respuesta a la solicitud inicial.

      Asimismo, el sistema ya no copia el encabezado de usuario-agente de la solicitud tunelizada a la solicitud proxy que configura el túnel. En lugar de eso, la biblioteca genera un título de usuario-agente para esa solicitud.

  • El método send(java.net.DatagramPacket) genera una SocketException si el método connect() ejecutado anteriormente falla.
    • DatagramSocket.connect() establece una pendingSocketException si existe un error interno. Antes de Android 8.0, una llamada recv() posterior generaba una SocketException aunque una llamada send() se realizara con éxito. Para lograr uniformidad, ambas llamadas ahora producen una SocketException.
  • InetAddress.isReachable() prueba el ICMP antes de volver al protocolo Echo TCP.
    • El acceso a algunos hosts que bloquean el puerto 7 (TCP Echo), como google.com, ahora es posible si estos aceptan el protocolo Echo ICMP.
    • Para hosts inaccesibles, este cambio significa que transcurre el doble de tiempo para que regrese la llamada.

Bluetooth

Android 8.0 presenta los siguientes cambios en la extensión de datos que obtiene el método ScanRecord.getBytes():

  • El método getBytes() no hace ningún cálculo respecto del número de bytes recibidos. Por lo tanto, las apps no deben depender de un número máximo o mínimo de bytes mostrados. En lugar de ello, deben evaluar la extensión de la matriz resultante.
  • Los dispositivos compatibles con Bluetooth 5 pueden mostrar una longitud de datos que excede el máximo anterior de ~60 bytes.
  • Si un dispositivo remoto no proporciona una respuesta detallada, también puede mostrarse un valor inferior a 60 bytes.

Conectividad sin inconvenientes

Android 8.0 realiza varias mejoras en la configuración Wi-Fi para facilitar la elección de la red de Wi-Fi que ofrece la mejor experiencia de usuario. Entre los cambios específicos se incluye lo siguiente:

  • Mejoras en la estabilidad y la confiabilidad.
  • Una IU de lectura más intuitiva.
  • Un menú consolidado y único de preferencias de Wi-Fi.
  • En dispositivos compatibles, la activación automática de la función Wi-Fi cuando se encuentre cerca una red de alta calidad guardada.

Seguridad

En Android 8.0 se incluyen los siguientes cambios relacionados con la seguridad:

  • La plataforma ya no es compatible con SSLv3.
  • Cuando se establece una conexión HTTPS con un servidor que implementa de manera incorrecta la negociación de versión de protocolo TLS, HttpsURLConnection deja de probar la alternativa de volver a versiones de protocolo TLS anteriores y realizar nuevos intentos.
  • Android 8.0 aplica un filtro de Secure Computing (SECCOMP) en todas las aplicaciones. La lista de todas las llamadas del sistema se restringe a aquellas que se exponen a través de bionic. Aunque se proporcionan varias llamadas de sistema para la compatibilidad con versiones anteriores, no recomendamos usarlas.
  • Ahora, los objetos WebView de tu aplicación se ejecutan en el modo multiproceso. Para mayor seguridad, el contenido de la web se controla en un proceso separado y aislado del proceso que contiene la app.
  • Ya no es posible suponer que los APK residen en directorios cuyos nombres terminen en -1 o -2. Las apps deben usar sourceDir para obtener un directorio y no depender directamente del formato de este.
  • Para obtener más información sobre las mejoras de seguridad relacionadas con el uso de bibliotecas nativas, consulta Bibliotecas nativas.

Para obtener pautas adicionales sobre cómo hacer que tu app sea más segura, consulta Seguridad para desarrolladores de Android.

Privacidad

Android 8.0 realiza en la plataforma los siguientes cambios relacionados con la privacidad.

  • Ahora, la plataforma maneja los identificadores de manera diferente.
    • Para aquellas apps que se instalaron antes de una actualización inalámbrica a una versión de Android 8.0 (nivel de API 26), el valor de ANDROID_ID sigue siendo el mismo a menos que se desinstalen y luego se reinstalen después de una actualización inalámbrica. Para preservar los valores en desinstalaciones después de una actualización inalámbrica, los desarrolladores pueden asociar los viejos valores con los nuevos usando copias de seguridad basadas en clave/valor.
    • En el caso de apps instaladas en un dispositivo con Android 8.0, el valor de ANDROID_ID ahora se define por clave de firma de app así como por usuario. El valor de ANDROID_ID es único para cada combinación de clave de firma de app, usuario y dispositivo. Como resultado, las apps con diferentes claves de firmas que se ejecutan en el mismo dispositivo dejan de detectar el mismo ID de Android (incluso para el mismo usuario).
    • En tanto la clave de firma sea la misma (y la app no se haya instalado antes de una actualización inalámbrica de una versión de O), el valor de ANDROID_ID no cambiará con la desinstalación o reinstalación del paquete.
    • El valor de ANDROID_ID no cambiará incluso si una actualización del sistema cambia la clave de firma del paquete.
    • Para un sistema estándar y simple destinado a monetizar apps, usa un ID de publicidad. El ID de publicidad es una identificación única para publicidad, proporcionada por Google Play Services, que el usuario puede restablecer.

  • La consulta de la propiedad del sistema net.hostname da como resultado el valor null.

Registro de excepciones no capturadas

Si una app instala una Thread.UncaughtExceptionHandler que no realiza una llamada a través del Thread.UncaughtExceptionHandler predeterminado, el sistema no finaliza la app cuando se produce una excepción no detectada. A partir de Android 8.0, el sistema registra el seguimiento de pila de la excepción en esta situación. En versiones anteriores de la plataforma, el sistema no registraba el rastro de pila de la excepción.

Recomendamos que las implementaciones de Thread.UncaughtExceptionHandler personalizados siempre realicen la llamada a través del controlador predeterminado. Las apps que siguen esta recomendación no se ven afectadas por el cambio en Android 8.0.

Cambio en las estadísticas del uso de proveedores de contactos

En versiones anteriores de Android, el componente de proveedores de contactos permite a los desarrolladores obtener los datos de uso para cada contacto. Estos datos de uso exponen información para cada dirección de correo electrónico y cada número de teléfono asociado con un contacto, incluido el número de veces que el contacto ha sido contactado y la última vez que fue contactado. Las apps que solicitan el permiso READ_CONTACTS pueden leer estos datos.

Las apps pueden leer estos datos si solicitan el permiso READ_CONTACTS. A partir de Android 8.0, las consultas sobre datos de uso muestran aproximaciones en lugar de valores exactos. El sistema Android mantiene internamente los valores exactos, por lo tanto este cambio no afecta las API de autocompletar.

Este cambio de comportamiento afecta los siguientes parámetros de consulta:

Manejo de recopilaciones

Ahora AbstractCollection.removeAll() y AbstractCollection.retainAll() generan siempre una NullPointerException. Anteriormente, la NullPointerException no se producía cuando la recopilación estaba vacía. Este cambio hace que el comportamiento se adecue a la documentación.

Android para empresas

Android 8.0 cambia el comportamiento de algunas API y funciones para apps empresariales, incluidos los controladores de políticas de dispositivos (DPC). Entre los cambios se incluye lo siguiente:

  • Nuevos comportamientos que permiten la compatibilidad de las apps con perfiles de trabajo en dispositivos completamente administrados.
  • Cambios en el manejo de actualizaciones del sistema, la verificación de apps y la autenticación para aumentar la integridad del dispositivo y del sistema.
  • Mejoras en la experiencia del usuario para aprovisionamiento, notificaciones, la pantalla Recientes y VPN siempre visibles.

Para ver todos los cambios empresariales en Android 8.0 y conocer el efecto que pueden tener sobre tu app, lee Android en la empresa.

Apps orientadas a Android 8.0

Estos cambios en el comportamiento se aplican exclusivamente a aplicaciones orientadas a la plataforma O ó a versiones posteriores. Las apps que se compilan para Android 8.0, y versiones posteriores, o que fijan targetSdkVersion en Android 8.0 y versiones posteriores, deben modificar sus apps para que admitan correctamente estos comportamientos, cuando corresponda.

Ventanas de alerta

Las apps que usan el permiso SYSTEM_ALERT_WINDOW ya no pueden usar los siguientes tipos de ventanas para mostrar ventanas de alerta sobre otras apps y ventanas del sistema:

Como alternativa, deben usar un nuevo tipo de ventana llamado TYPE_APPLICATION_OVERLAY.

Al usar el tipo de ventana TYPE_APPLICATION_OVERLAY a fin de mostrar ventanas de alerta para tu aplicación, ten en cuenta las siguientes características del nuevo tipo de ventana:

  • Las ventanas de alerta de una aplicación siempre aparecerán en ventanas críticas del sistema, como la barra de estado y los IME.
  • El sistema puede mover las ventanas que usan el tipo de ventana TYPE_APPLICATION_OVERLAY o cambiar el tamaño de estas para mejorar la presentación en la pantalla.
  • Al abrir el panel de notificaciones, los usuarios pueden acceder a ajustes para bloquear en una app la visualización de ventanas de alerta que se muestran con el tipo de ventana TYPE_APPLICATION_OVERLAY.

Notificaciones de cambios de contenido

Android 8.0 cambia el comportamiento de ContentResolver.notifyChange() y registerContentObserver(Uri, boolean, ContentObserver) en el caso de las apps orientadas a Android 8.0.

Estas API ahora solicitan la definición de un ContentProvider válido para la autoridad en todos los URI. La definición de un ContentProvider válido con permisos correspondientes ayudará a proteger tu aplicación contra cambios de contenido desde aplicaciones maliciosas y prevendrán la posible fuga de datos privados hacia estas aplicaciones.

Enfoque de las vistas

Los objetos seleccionables View ahora también pueden enfocarse de manera predeterminada. Si deseas que un objeto View sea seleccionable y no pueda enfocarse, fije el atributo android:focusable en false en el archivo XML de diseño que contiene la View o pasa false a setFocusable() en la lógica de IU de tu app.

Seguridad

Si en la configuración de seguridad de red de tu app se desactiva la compatibilidad con tráfico de Cleartext, los objetos WebView de tu app no pueden acceder a los sitios web mediante HTTP. Como alternativa, cada objeto WebView debe usar el protocolo HTTPS.

Para obtener pautas adicionales sobre cómo hacer que tu app sea más segura, consulta Seguridad para desarrolladores de Android.

Acceso y visibilidad para cuentas

Las apps ya no pueden acceder a las cuentas de usuario a menos que el autenticador las posea o el usuario otorgue acceso a ellas. El permiso GET_ACCOUNTS ya no es suficiente. Para obtener acceso a una cuenta, las aplicaciones deben usar AccountManager.newChooseAccountIntent() o un método específico de autenticador. Después de obtener acceso a las cuentas, una aplicación puede llamar a AccountManager.getAccounts() para concretar el acceso.

En Android 8.0, LOGIN_ACCOUNTS_CHANGED_ACTION deja de estar disponible. Como alternativa, las apps deben usar addOnAccountsUpdatedListener() para obtener actualizaciones sobre las cuentas durante el tiempo de ejecución.

Si deseas obtener más información sobre las API y los métodos nuevos de acceso y visibilidad para cuentas, consulta Acceso y visibilidad para cuentas en la sección Nuevas API de este documento.

Privacidad

Los siguientes cambios afectan la privacidad en Android 8.0.

  • Las propiedades de sistema net.dns1, net.dns2, net.dns3 y net.dns4 ya no están disponibles, un cambio que mejora la privacidad en la plataforma.
  • Para obtener información de red, como la de servidores DNS, las apps con el permiso ACCESS_NETWORK_STATE pueden registrar un objeto NetworkRequest o NetworkCallback. Estas clases están disponibles en Android 5.0 (nivel de API 21) y versiones posteriores.
  • Build.SERIAL es obsoleto. Las apps que necesitan conocer el número de serie del hardware deben usar en cambio el nuevo método Build.getSerial(), que requiere el permiso READ_PHONE_STATE.
  • La API LauncherApps ya no permite que las apps de perfil de trabajo obtengan información sobre el perfil principal. Cuando un usuario está en un perfil de trabajo, la API LauncherApps se comporta como si no se instalaran apps en otros perfiles dentro del mismo grupo de perfil. Como antes, los intentos de acceder a perfiles no relacionados generan SecurityExceptions.

Permisos

Antes de Android 8.0, si una app solicitaba un permiso en el tiempo de ejecución y este se otorgaba, el sistema también otorgaba a esta, de manera incorrecta, el resto de los permisos que pertenecían al mismo grupo de permisos y estaban registrados en el manifiesto.

Para las aplicaciones orientadas a Android 8.0, se ha corregido este comportamiento. La app solo obtiene los permisos que ha solicitado explícitamente. Sin embargo, una vez que el usuario otorga permiso a la app, todas las solicitudes de permisos posteriores de ese grupo de permisos se otorgan de manera automática.

Por ejemplo, supón que una aplicación presenta READ_EXTERNAL_STORAGE y WRITE_EXTERNAL_STORAGE en su manifiesto. La aplicación solicita READ_EXTERNAL_STORAGE y el usuario lo otorga. Si la aplicación tiene como objetivo el nivel de API 24 o niveles inferiores, el sistema también otorga WRITE_EXTERNAL_STORAGE al mismo tiempo, porque pertenece al mismo grupo de permisos STORAGE y también está registrado en el manifiesto. Si la app está orientada a Android 8.0, el sistema solo otorga READ_EXTERNAL_STORAGE en ese momento. Sin embargo, si la app luego solicita WRITE_EXTERNAL_STORAGE, el sistema inmediatamente otorga ese privilegio sin notificar al usuario.

Medios

  • El marco de trabajo aplica atenuación de audio. Las aplicaciones no pierden el foco en el caso de AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK. Se encuentran disponibles API nuevas para apps que deben hacer una pausa en lugar de aplicar atenuación automática. Ten en cuenta que este comportamiento no se implementó en Android 8.0 1.
  • Cuando el usuario recibe una llamada telefónica, los flujos de medios activos se silencian hasta que esta finaliza.
  • Todas las API relacionadas con el audio deben usar AudioAttributes en lugar de tipos de transmisiones de audio para describir el caso de uso de reproducción de audio. Continúa usando los tipos de transmisión de audio únicamente para los controles de volumen. Otros usos de tipos de transmisión (como AudioTrack constructor, ya obsoleto) aún funcionan, pero el sistema los carga como un error.
  • Cuando se use un AudioTrack, si la aplicación solicita un búfer de audio suficientemente grande, el marco de trabajo intentará usar la salida de búfer profundo si se encuentra disponible.
  • En Android 8.0, el manejo de eventos de botones multimedia es diferente:
    1. El manejo de botones multimedia en una actividad de IU no ha cambiado: las actividades de primer plano aún tienen prioridad en el manejo de botones multimedia.
    2. Si la actividad en primer plano no maneja el botón multimedia, el sistema direcciona botones multimedia hacia la app que más recientemente reprodujo el audio de manera local. Ya no se tienen en cuenta el estado activo, los indicadores ni el estado de reproducción de una sesión multimedia cuando se determina la app que recibe eventos de botones multimedia. Las sesiones multimedia pueden recibir eventos de botones multimedia incluso después de que la app llama a setActive(false).
    3. Si la sesión multimedia de la app se ha lanzado, el sistema envía el evento de botones multimedia al MediaButtonReceiver de la app, si tiene uno.
    4. Para cualquier otro caso, el sistema descarta el evento de botón multimedia. Es mejor no ejecutar nada que ejecutar la app equivocada.

    En el siguiente diagrama se muestra un resumen de la nueva lógica de direccionamiento de botones multimedia:

    Direccionamiento de botones multimedia

Bibliotecas nativas

En apps orientadas a Android 8.0, las bibliotecas nativas ya no se cargan si contienen un segmento de carga que admite escritura y ejecución. Algunas apps pueden dejar de funcionar debido a este cambio si tienen bibliotecas nativas con segmentos de carga incorrectos. Esta es una medida para reforzar la seguridad.

Para obtener más información, consulta Segmentos que admiten escritura y ejecución.

Como en el caso de las anteriores, Android 8.0 también hace más visibles todos los problemas relacionados con vinculadores. Los cambios de vinculadores están unidos al nivel de API que una app tiene como objetivo. Si se produce un cambio de vinculador en el nivel de API de objetivo, la app no puede cargar la biblioteca. Si tienes como objetivo un nivel de API inferior al nivel de API en el que se produce el cambio de vinculador, logcat muestra una advertencia. Durante el lanzamiento de una versión preliminar, los problemas relacionados con vinculadores no solo aparecen en el logcat, sino también se muestran como notificaciones. Este cambio mejora la visibilidad de los problemas antes del nivel de API en el cual una advertencia se convierte en error.

Manejo de recopilaciones

En Android 8.0, Collections.sort() se implementa sobre List.sort(). Sucedía lo contrario en Android 7.x (niveles de API 24 y 25): La implementación predeterminada de List.sort() se llama Collections.sort().

Este cambio permite a Collections.sort() aprovechar implementaciones optimizadas de List.sort(), pero tiene las siguientes limitaciones:

  • Las implementaciones de List.sort() no deben llamar a Collections.sort() porque puede producirse un desbordamiento de pila debido a una recurrencia infinita. Por el contrario, si deseas el comportamiento predeterminado en tu implementación de List, debes evitar anular sort().

    Si una clase primaria implementa sort() de forma inapropiada, normalmente está bien anular List.sort() con una implementación compilada sobre List.toArray(), Arrays.sort() y ListIterator.set(). Por ejemplo:

    @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);
      }
    }
    

    En la mayoría de los casos, también puedes anular List.sort() con una implementación que se delegue a diferentes implementaciones predeterminadas según el nivel de API. Por ejemplo:

    @Override
    public void sort(Comparator<? super E> comparator) {
      if (Build.VERSION.SDK_INT <= 25) {
        Collections.sort(this);
      } else {
        super.sort(comparator);
      }
    }
    

    Si haces esto último solo porque deseas tener un método sort() disponible en todos los niveles de API, considera darle un nombre único como sortCompat(), en vez de anular sort().

  • Collections.sort() ahora cuenta como una modificación estructural en las implementaciones de List que llaman a sort(). Por ejemplo, en versiones de la plataforma anteriores a Android 8.0, aplicar iteraciones sobre un ArrayList y llamar a sort() a medio camino a través de la iteración habría generado una ConcurrentModificationException si el ordenamiento se hubiera realizado llamando a List.sort(). Collections.sort() no generó una excepción.

    Este cambio hace que el comportamiento de la plataforma sea más uniforme: Cualquiera de los enfoques ahora genera una ConcurrentModificationException.

Comportamiento de carga de clases

Android 8.0 realiza algunas comprobaciones para garantizar que los cargadores de clases no transgredan las suposiciones de tiempo de ejecución cuando se cargan clases nuevas. Estas comprobaciones se realizan si se hace referencia a la clase desde Java (desde forName()), Dalvik bytecode o JNI. La plataforma no intercepta llamadas directas de Java al método loadClass(), ni comprueba los resultados de dichas llamadas. Este comportamiento no debe afectar el funcionamiento de los cargadores de clases eficientes.

La plataforma comprueba que el descriptor de la clase que muestra el cargador de clases coincida con el descriptor esperado. Si el descriptor que se muestra no coincide, la plataforma genera un error NoClassDefFoundError y en la excepción se almacena un mensaje detallado en el cual se menciona la discrepancia.

La plataforma también comprueba que los descriptores de las clases solicitadas sean válidos. Esta comprobación detecta llamadas JNI que indirectamente cargan clases como GetFieldID(), y se pasan descriptores inválidos a esas clases. Por ejemplo, no se encuentra un campo con firma java/lang/String debido a que la firma no es válida; debe ser Ljava/lang/String;.

Esto difiere de una llamada JNI a FindClass() en la cual java/lang/String es un nombre válido y completamente calificado.

Android 8.0 no admite que varios cargadores de clases intenten definir clases usando el mismo objeto DexFile. Un intento de hacerlo da como resultado que el tiempo de ejecución de Android genere un error InternalError con el mensaje “Attempt to register dex file <filename> with multiple class loaders” (intento de registrar un archivo dex con varios cargadores de clases).

Ahora la API de DexFile es obsoleta y te recomendamos firmemente usar uno de los cargadores de clases de la plataforma, incluidos PathClassLoader o BaseDexClassLoader, como alternativa.

Nota: Puedes crear varios cargadores de clases que hagan referencia al mismo contenedor de archivo APK o JAR desde el sistema de archivos. Normalmente, hacer esto no genera demasiada sobrecarga de memoria: si los archivos DEX del contenedor se almacenan en lugar de comprimirse, la plataforma puede realizar una operación mmap sobre ellos en vez de extraerlos directamente. Sin embargo, si la plataforma debe extraer el archivo DEX del contenedor, hacer referencia a un archivo DEX de este modo puede consumir mucha memoria.

En Android, se considera que todos los cargadores de clases tienen capacidad paralela. Cuando varios subprocesos compiten para cargar la misma clase con el mismo cargador de clases, el primer subproceso en completar la operación gana y el resultado se usa para los otros subprocesos. Este comportamiento ocurre sin importar si el cargador de clases mostró la misma clase o una diferente, o si produjo una excepción. La plataforma ignora de forma automática esas excepciones.

Advertencia: En versiones de la plataforma inferiores a Android 8.0, la transgresión de estas suposiciones pueden hacer que se defina la misma clase varias veces, se dañe el montón debido a la confusión de clases y se generen otros resultados no deseables.