Nivel de API: 17
Android 4.2 (JELLY_BEAN_MR1
)
es una actualización del lanzamiento de Jelly Bean que ofrece nuevas funciones para los usuarios
desarrolladores. En este documento, se ofrece una introducción a las APIs nuevas más distinguidas y útiles para los desarrolladores.
Si eres desarrollador de apps, debes descargar la imagen del sistema Android 4.2 y la plataforma del SDK desde SDK Manager lo antes posible. Si no tienes un dispositivo con Android 4.2 en el cual probar tu app, usa la imagen del sistema de Android 4.2 para probarla en el emulador de Android. Luego, compila las apps con la plataforma Android 4.2 para comenzar a usar las APIs más recientes.
Para optimizar mejor tu app para dispositivos con Android 4.2, debes configurar tu targetSdkVersion
en "17"
, instalarla en una imagen del sistema Android 4.2, probarla y, luego, publicar una actualización con este cambio.
Tú
puedes usar APIs en Android 4.2 y, al mismo tiempo, admitir versiones anteriores agregando
condiciones a tu código que comprueben el nivel de API del sistema antes de la ejecución
APIs no compatibles con tu minSdkVersion
.
Para obtener más información sobre cómo mantener la retrocompatibilidad, consulta Cómo crear IU retrocompatibles.
Puedes encontrar más información sobre el funcionamiento de los niveles de API en Qué es la API nivel?
Importantes cambios en los comportamientos
Si publicaste anteriormente una app para Android, ten en cuenta lo siguiente: cambios que podrían afectar el comportamiento de tu app:
- Los proveedores de contenido ya no se exportan de forma predeterminada. Es decir, el valor predeterminado
del atributo
android:exported
ahora es“false"
. Si es importante que otras apps acceder a tu proveedor de contenido, ahora debes configurarandroid:exported="true"
de forma explícita.Este cambio se aplica solo si estableces
android:targetSdkVersion
oandroid:minSdkVersion
en 17 o una versión posterior. De lo contrario, el valor predeterminado sigue siendo“true"
incluso cuando se ejecuta en Android 4.2 y versiones posteriores. - En comparación con versiones anteriores de Android, los resultados de la ubicación del usuario pueden ser menos precisos si tu app solicita el permiso
ACCESS_COARSE_LOCATION
, pero no solicita el permisoACCESS_FINE_LOCATION
.Para cumplir con las expectativas de privacidad de los usuarios cuando la app solicita permiso para lo siguiente: ubicación aproximada (y no precisa), el sistema no proporcionará una estimación de la ubicación del usuario que es más preciso que una manzana.
- Algunos parámetros de configuración del dispositivo definidos por
Settings.System
ahora son de solo lectura. Si tu app intenta escribir cambios en la configuración definida enSettings.System
que se movieron aSettings.Global
, ocurrirá lo siguiente: La operación de escritura fallará silenciosamente cuando se ejecute en Android 4.2 y versiones posteriores.Incluso si el valor de
android:targetSdkVersion
yandroid:minSdkVersion
es inferior a 17, tu app no puede modificar la configuración que se trasladó aSettings.Global
cuando se ejecuta en Android 4.2 y versiones posteriores. - Si tu app usa
WebView
, Android 4.2 agrega una capa adicional de para que puedas vincular JavaScript a tu Código de Android Si configuraste tutargetSdkVersion
en 17 o un valor posterior, ahora debes agregar la anotación@JavascriptInterface
a cualquier método que desees que esté disponible para el código de JavaScript (el método también debe ser público). Si no proporcionas la anotación, no se puede acceder al método desde una página web en tuWebView
cuando se ejecuta en Android 4.2 o versiones posteriores. Si configurastargetSdkVersion
en 16 o menos, no se requiere la anotación, pero te recomendamos que actualices la versión de destino y agregues la anotación para mayor seguridad.Más información sobre la vinculación Código JavaScript a código de Android.
Daydream
Daydream es un nuevo modo de protector de pantalla interactivo para dispositivos Android. Se activa automáticamente cuando el dispositivo se inserta en una estación de carga o cuando se deja inactivo mientras está conectado a un cargador (en lugar de apagar la pantalla). Daydream muestra un sueño a la vez, lo que puede ser una pantalla puramente visual y pasiva que se descarta con el tacto o puede ser interactiva y responsiva al kit completo de eventos de entrada. Tus sueños se desarrollan en el proceso de tu app y tienen acceso completo a el kit de herramientas de IU de Android, que incluye vistas, diseños y animaciones, para que sean más flexibles y potentes que los fondos de pantalla animados o los widgets de apps.
Puedes crear un sueño para Daydream implementando una subclase de DreamService
. Las APIs de DreamService
son
diseñados para ser similares a los de Activity
. Para especificar la IU de tu sueño, pasa un ID de recurso de diseño o View
a setContentView()
en cualquier momento después de que tengas una ventana, como desde la devolución de llamada de onAttachedToWindow()
.
La clase DreamService
proporciona otros métodos importantes de devolución de llamada del ciclo de vida además de las APIs de Service
básicas, como onDreamingStarted()
, onDreamingStopped()
y onDetachedFromWindow()
.
No puedes iniciar una DreamService
desde tu
la aplicación, el sistema la inicia automáticamente.
Si tu sueño es interactivo, puedes iniciar una actividad desde el sueño para enviar al usuario
la IU completa de tu app para obtener más detalles o control. Puedes usar finish()
para finalizar el sueño, de modo que el usuario pueda ver el
actividad nueva.
Para que tu daydream esté disponible para el sistema, declara tu DreamService
con un elemento <service>
.
en tu archivo de manifiesto. Luego, debes incluir un filtro de intents con la acción "android.service.dreams.DreamService"
. Por ejemplo:
<service android:name=".MyDream" android:exported="true" android:icon="@drawable/dream_icon" android:label="@string/dream_label" > <intent-filter> <action android:name="android.service.dreams.DreamService" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </service>
Hay otros métodos útiles en DreamService
debes tener en cuenta:
setInteractive(boolean)
controla si El sueño recibe eventos de entrada o sale inmediatamente después de la entrada del usuario. Si el sueño es interactivo, el usuario puede usar los botones Atrás o Inicio para salir del sueño, o bien puedes llamar afinish()
para detenerlo.- Si quieres una pantalla completamente envolvente, puedes llamar a
setFullscreen()
para ocultar la barra de estado. - Antes de que se inicie el protector de pantalla interactivo, la pantalla se atenúa para indicarle al usuario que el tiempo de espera de inactividad
se acerca. Llamar a
setScreenBright(true)
te permite configurar la pantalla con el brillo habitual.
Para obtener más información, consulta la documentación de DreamService
.
Pantallas secundarias
Android ahora permite que tu app muestre contenido único en pantallas adicionales que están conectadas
al dispositivo del usuario a través de una conexión con cable o Wi-Fi.
Para crear contenido único para una pantalla secundaria, extiende la clase Presentation
e implementa la devolución de llamada onCreate()
. En un radio de
onCreate()
, especifica la IU para la pantalla secundaria
llamando a setContentView()
.
Como una extensión de la clase Dialog
, la clase Presentation
proporciona la región en la que tu app puede mostrar una IU única en la pantalla secundaria.
Para detectar pantallas secundarias en las que puedes mostrar tu Presentation
,
usa DisplayManager
o MediaRouter
.
APIs Si bien las APIs de DisplayManager
te permiten enumerar varias pantallas que pueden estar conectadas a la vez, por lo general, debes usar MediaRouter
para acceder rápidamente a la pantalla predeterminada del sistema para las presentaciones.
Para obtener la pantalla predeterminada de tu presentación, llama a MediaRouter.getSelectedRoute()
y pásale ROUTE_TYPE_LIVE_VIDEO
. Esto muestra un objeto MediaRouter.RouteInfo
que describe la ruta seleccionada actualmente por el sistema para las presentaciones de video. Si MediaRouter.RouteInfo
no es nulo, llama a getPresentationDisplay()
para obtener el Display
que representa la pantalla conectada.
Luego, puedes mostrar tu presentación pasando el objeto Display
.
a un constructor para la clase Presentation
. Ahora, tu presentación
en la pantalla secundaria.
Para detectar en el tiempo de ejecución cuándo se conectó una pantalla nueva, crea una instancia de MediaRouter.SimpleCallback
en la que implementes el método de devolución de llamada onRoutePresentationDisplayChanged()
, al que el sistema llamará cuando se conecte una nueva pantalla de presentación. Luego, registra el MediaRouter.SimpleCallback
pasándolo a MediaRouter.addCallback()
junto con el tipo de ruta ROUTE_TYPE_LIVE_VIDEO
. Cuando recibas una llamada a onRoutePresentationDisplayChanged()
, simplemente llama a MediaRouter.getSelectedRoute()
como se mencionó anteriormente.
Para optimizar aún más la IU en tu Presentation
para
pantallas secundarias, puedes aplicar
un tema diferente especificando el atributo android:presentationTheme
en el <style>
que
aplicarse a tu aplicación o actividad.
Ten en cuenta que las pantallas conectadas al dispositivo del usuario suelen tener un tamaño de pantalla más grande y, probablemente, una densidad de pantalla diferente. Debido a que las características de la pantalla pueden ser diferentes, debes proporcionar recursos optimizados específicamente para esas pantallas más grandes. Si necesitas solicitar recursos adicionales de tu Presentation
, llama a getContext()
.getResources()
para obtener el objeto Resources
correspondiente a la pantalla. Esto proporciona
para conocer los recursos adecuados de tu app
la densidad y el tamaño de la pantalla secundaria.
Para obtener más información y algunos ejemplos de código, consulta la documentación de la clase Presentation
.
Widgets de la pantalla de bloqueo
Android ahora permite que los usuarios agreguen widgets de apps a la pantalla de bloqueo. Para que el widget de la app esté disponible para usarse en la pantalla de bloqueo, agrega el atributo android:widgetCategory
al archivo en formato XML que especifica el AppWidgetProviderInfo
. Este atributo admite dos valores: home_screen
y keyguard
. De forma predeterminada, el atributo se establece en home_screen
para que los usuarios puedan agregar el widget de tu app a la pantalla principal. Si quieres que el widget de tu app también esté disponible en la pantalla de bloqueo, agrega el valor keyguard
:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" ... android:widgetCategory="keyguard|home_screen"> </appwidget-provider>
También debes especificar un diseño inicial para el widget de tu app en la pantalla de bloqueo con
el atributo android:initialKeyguardLayout
. Funciona de la misma manera que android:initialLayout
, ya que proporciona un diseño que puede aparecer de inmediato hasta que se inicializa el widget de tu app y puede actualizar el diseño.
Para obtener más información sobre la compilación de widgets de apps para la pantalla de bloqueo, incluido el tamaño correcto del widget de la app cuando está en la pantalla de bloqueo, consulta la guía Widgets de apps.
Varios usuarios
Android ahora permite múltiples espacios de usuario en dispositivos que se pueden compartir, como tablets. Cada usuario de un dispositivo tiene su propio conjunto de cuentas, apps, parámetros de configuración del sistema, archivos y cualquier otro dato asociado al usuario.
Como desarrollador, no necesitas hacer nada diferente para que tu app funcione correctamente con varios usuarios en un solo dispositivo. Independientemente de la cantidad de usuarios que puedan existir en un dispositivo, los datos que guarda tu app para un usuario determinado se mantienen separados de los datos que guarda tu app para otros usuarios. El sistema realiza un seguimiento de los datos del usuario que pertenecen al proceso de usuario en el que se ejecuta tu app y le proporciona acceso solo a los datos de ese usuario y no permite el acceso a los datos de otros usuarios.
Guarda datos en un entorno multiusuario
Siempre que tu app guarde las preferencias del usuario, cree una base de datos o escriba un archivo en la en un espacio de almacenamiento interno o externo, solo se podrá acceder a esos datos mientras se ejecuten como ese usuario.
Para asegurarte de que tu app se comporte correctamente en un entorno multiusuario, no consultes tu directorio interno de la app o ubicación de almacenamiento externo por medio de rutas hard-coded y, en su lugar, usar siempre las APIs adecuadas:
- Para acceder al almacenamiento interno, usa
getFilesDir()
,getCacheDir()
oopenFileOutput()
. - Para acceder al almacenamiento externo, usa
getExternalFilesDir()
ogetExternalStoragePublicDirectory()
.
Independientemente de cuál de estas APIs uses para guardar datos de un usuario determinado, los datos no se y accesibles mientras se ejecuta como un usuario diferente. Desde el punto de vista de tu app, cada usuario ejecuta en un dispositivo completamente independiente.
Identifica usuarios en un entorno multiusuario
Si tu app desea identificar usuarios únicos, por ejemplo, para recopilar estadísticas o crear otras asociaciones de cuenta, debes seguir las prácticas recomendadas para identificar instalaciones únicas. Si creas un nuevo elemento UUID
cuando se inicie tu app para la
primera vez, se asegurará de obtener un ID único para realizar el seguimiento de cada usuario, independientemente de la
usuarios instalan tu app en un solo dispositivo. También puedes guardar un token local recuperado de
tu servidor o usa el ID de registro que proporciona Google Cloud Messaging.
Ten en cuenta que si tu app solicita uno de los identificadores de dispositivos de hardware (como el identificador de MAC de Wi-Fi
dirección IP o el número de SERIAL
), proporcionarán el mismo valor para cada
usuario porque estos identificadores
están vinculados al hardware y no al usuario. Sin mencionar los otros problemas que introducen estos identificadores, como se explica en la entrada de blog Cómo identificar las instalaciones de aplicaciones.
Nueva configuración global
Se actualizó la configuración del sistema para admitir varios usuarios con la adición de Settings.Global
. Este conjunto de parámetros de configuración es similar a los de Settings.Secure
porque son de solo lectura, pero se aplican globalmente en
a todos los espacios de usuario del dispositivo.
Varios parámetros de configuración existentes se trasladaron aquí, ya sea de Settings.System
o Settings.Secure
. Si tu app está realizando cambios en la configuración definida anteriormente en Settings.System
(como AIRPLANE_MODE_ON
), debes esperar que, si esos parámetros de configuración se movieron a Settings.Global
, ya no funcione en un dispositivo con Android 4.2 o versiones posteriores. Puedes seguir leyendo la configuración que se encuentra en
Settings.Global
, pero debido a que la configuración ya no se considera segura
para que las apps cambien, intentar hacerlo fallará silenciosamente y el sistema escribirá una advertencia a
el registro del sistema cuando ejecutas tu app en Android 4.2 o versiones posteriores.
Compatibilidad con el diseño de derecha a izquierda
Android ahora ofrece varias APIs que te permiten compilar interfaces de usuario que transformen con elegancia la orientación del diseño para admitir idiomas que usan IU y dirección de lectura de derecha a izquierda (RTL), como el árabe y el hebreo.
Para comenzar a admitir diseños de RTL en tu app, establece el atributo android:supportsRtl
en el elemento <application>
de tu archivo de manifiesto y configúralo como “true"
. Cuando habilites esto, el sistema habilitará varias APIs de RTL para
mostrar tu app con diseños RTL. Por ejemplo, la barra de acciones mostrará el ícono y el título.
a la derecha y los botones de acción a la izquierda, y cualquier diseño que hayas creado con el
También se revertirán las clases View
proporcionadas por el framework.
Si necesitas optimizar aún más la apariencia de tu app cuando se muestra con un diseño de derecha a izquierda, existen dos niveles básicos de optimización:
- Convierte las propiedades de diseño orientadas a la izquierda y la derecha en un diseño orientado al inicio y al final
propiedades.
Por ejemplo, usa
android:layout_marginStart
. en lugar deandroid:layout_marginLeft
yandroid:layout_marginEnd
en lugar deandroid:layout_marginRight
.La clase
RelativeLayout
también proporciona el diseño correspondiente. atributos para reemplazar las posiciones izquierda/derecha, comoandroid:layout_alignParentStart
para reemplazarandroid:layout_alignParentLeft
yandroid:layout_toStartOf
en lugar deandroid:layout_toLeftOf
- O bien, para proporcionar una optimización completa para los diseños RTL, puedes proporcionar instrucciones completamente separadas
archivos de diseño que usan el calificador de recursos
ldrtl
(ldrtl
significa diseño-dirección-de-derecha a izquierda}). Por ejemplo, puedes guardar tus archivos de diseño predeterminados enres/layout/
y tus diseños optimizados para la escritura de derecha a izquierda enres/layout-ldrtl/
.El calificador
ldrtl
es ideal para los recursos de elementos de diseño, de modo que puedas proporcionar gráficos orientados en la dirección correspondiente a la dirección de lectura.
Hay varias otras APIs disponibles en el framework para admitir diseños RTL, como en la
clase View
, de modo que puedas implementar los comportamientos adecuados para las vistas
personalizadas y en Configuration
para consultar la dirección del diseño actual.
Nota: Si usas SQlite y tienes nombres de tablas o columnas que son "solo números", ten cuidado: usar String.format(String, Object...)
puede generar errores en los que los números se hayan convertido a sus equivalentes en árabe si tu dispositivo está configurado en la configuración regional del árabe.
Debes usar String.format(Locale,String,Object...)
para asegurarte de que los números se conserven como ASCII. También usa String.format("%d", int)
en lugar de String.valueOf(int)
para dar formato a los números.
Fragmentos anidados
Ahora puedes incorporar fragmentos dentro de fragmentos. Esto es útil para una variedad de situaciones en las que deseas colocar componentes de IU dinámicos y reutilizables en un componente de IU que también es dinámico y reutilizable. Por ejemplo, si usas ViewPager
para
crear fragmentos que se puedan deslizar hacia la izquierda y la derecha, y ocupen la mayor parte del espacio de la pantalla, puedes
ahora insertar fragmentos en cada página de fragmento.
Para anidar un fragmento, simplemente llama a getChildFragmentManager()
en el Fragment
en el que deseas agregar un fragmento. Esto muestra un FragmentManager
que puedes usar como lo haces normalmente desde la actividad de nivel superior para crear transacciones de fragmentos. Por ejemplo, aquí tienes código que agrega un fragmento desde adentro
una clase Fragment
existente:
Kotlin
val videoFragment = VideoPlayerFragment() childFragmentManager.beginTransaction().apply { add(R.id.video_fragment, videoFragment) commit() }
Java
Fragment videoFragment = new VideoPlayerFragment(); FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); transaction.add(R.id.video_fragment, videoFragment).commit();
Desde un fragmento anidado, puedes obtener una referencia al fragmento superior llamando a getParentFragment()
.
La biblioteca de compatibilidad de Android ahora también admite fragmentos anidados, por lo que puedes implementar de fragmentos en Android 1.6 y versiones posteriores.
Nota: No puedes aumentar un diseño en un fragmento cuando ese diseño
incluye un <fragment>
. Los fragmentos anidados solo se admiten cuando se agregan a un fragmento de forma dinámica.
RenderScript
Se mejoró la funcionalidad de procesamiento de Renderscript con las siguientes características:
- Funciones intrínsecas de secuencias de comandos
Puedes usar las funciones intrínsecas de secuencias de comandos integradas de Renderscript para implementar operaciones comunes para ti, como las siguientes:
Blends
Blur
Color matrix
3x3 convolve
5x5 convolve
Per-channel lookup table
Converting an Android YUV buffer to RGB
Para usar un elemento intrínseco de secuencia de comandos, llama al método
create()
estático de cada elemento intrínseco para crear una instancia de la secuencia de comandos. Luego, llamarás alset()
disponible de cada secuencia de comandos intrínseca para configurar las entradas y opciones necesarias. Por último, llama al métodoforEach()
para ejecutar la secuencia de comandos.- Grupos de secuencias de comandos
-
Los elementos
ScriptGroup
te permiten encadenar los RenderScript relacionados. de comandos de shell y ejecutarlas con una llamada.Usa un
ScriptGroup.Builder
para agregar todas las secuencias de comandos al grupo llamando aaddKernel()
. Una vez que agregar todas las secuencias de comandos, crear las conexiones entre de comandos llamando aaddConnection()
. Cuando termines de agregar las conexiones, llama acreate()
para crear el grupo de secuencias de comandos. Antes de ejecutar el grupo de secuencias de comandos, especifica la entradaAllocation
y la secuencia de comandos inicial que se ejecutará con el métodosetInput(Script.KernelID, Allocation)
, y proporciona la salidaAllocation
en la que se escribirá el resultado y la secuencia de comandos final que se ejecutará consetOutput()
. Por último, llamaexecute()
para ejecutar el grupo de secuencias de comandos. - Filterscript
-
Filterscript define restricciones en las APIs de Renderscript existentes que permiten que el código resultante se ejecute en una variedad más amplia de procesadores (CPU, GPU y DSP). Para crear archivos de Filterscript, crea
.fs
. en lugar de archivos.rs
, y especifica#pragma rs_fp_relaxed
como Indícale al entorno de ejecución de Renderscript que tus secuencias de comandos no requieren una precisión estricta de punto flotante IEEE 754-2008. Esta precisión permite el vaciado a cero para denormales y el redondeo a cero. Además, tus secuencias de comandos de Filterscript no deben usar tipos integrados de 32 bits y deben especificar una función raíz personalizada con el atributo__attribute__((kernel))
, ya que Filterscript no admite punteros, que define la firma predeterminada de la funciónroot()
.
Nota: Si bien la compatibilidad de Filterscript está en la plataforma, el desarrollador asistencia estará disponible en la versión 21.0.1 de las herramientas del SDK.
Para obtener una vista detallada de todos los cambios de las APIs en Android 4.2, consulta el Informe de diferencias de las APIs.