Nivel de API: 17
Android 4.2 (JELLY_BEAN_MR1
)
es una actualización del lanzamiento de Jelly Bean que ofrece nuevas funciones a los usuarios
desarrolladores. Este documento proporciona una introducción a los conceptos más destacados
APIs nuevas y útiles para desarrolladores.
Como desarrollador de aplicaciones, debes descargar la imagen del sistema Android 4.2 y la plataforma SDK desde SDK Manager lo antes posible. Si no tienes un dispositivo con Android 4.2 en el cual probar la app, usa el sistema Android 4.2 para probar la app en el emulador de Android. Luego, compila tus 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, haz lo siguiente:
Debes configurar tu targetSdkVersion
como
"17"
, instálala en una imagen del sistema Android 4.2
probarlo 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
mantener la retrocompatibilidad, lee Cómo crear retrocompatibilidad
más recientes.
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 solo se aplica si estableces
android:targetSdkVersion
oandroid:minSdkVersion
en 17 o un valor superior. De lo contrario, el valor predeterminado sigue siendo“true"
. incluso con 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 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 para
android:targetSdkVersion
yandroid:minSdkVersion
es inferior a 17, la app no podrá modificar los parámetros 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 establecestargetSdkVersion
a 17 o versiones posteriores, ahora debes agregar la anotación@JavascriptInterface
a cualquier método que estén disponibles para tu 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 establecestargetSdkVersion
a 16 o menos, la anotación no es obligatoria, pero te recomendamos que actualices la versión de destino y agrega 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 un conector o cuando el dispositivo permanece inactivo mientras está conectado a una (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
pasar un ID de recurso de diseño o View
a setContentView()
en cualquier momento después de
una ventana, como onAttachedToWindow()
devolución de llamada.
La clase DreamService
proporciona otra devolución de llamada importante del ciclo de vida.
sobre las APIs de Service
base, 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>
Existen 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 puedes llamarfinish()
para detener el sueño.- 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.
Si quieres crear contenido único para una pantalla secundaria, extiende Presentation
e implementar 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 conectarse a la vez, por lo general, debes usar MediaRouter
en su lugar para acceder rápidamente a la pantalla predeterminada del sistema para
presentaciones.
Para obtener la pantalla predeterminada de tu presentación, llama a MediaRouter.getSelectedRoute()
y pásala
ROUTE_TYPE_LIVE_VIDEO
Se mostrará un objeto MediaRouter.RouteInfo
que describe la ruta seleccionada actualmente del sistema.
para las presentaciones en 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 durante el tiempo de ejecución cuando se conecta 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 cree una nueva
la pantalla de presentación esté conectada. Luego, registra el MediaRouter.SimpleCallback
pasándolo a MediaRouter.addCallback()
junto con el tipo de ruta ROUTE_TYPE_LIVE_VIDEO
. Cuando recibes 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
proporcionan recursos optimizados específicamente para pantallas más grandes. Si necesitas
Para 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 algunas muestras de código, consulta el archivo Presentation
.
la documentación de la clase.
Widgets de pantalla de bloqueo
Android ahora permite a los usuarios agregar widgets de apps a la pantalla de bloqueo. Para que el widget de la app esté disponible en la
pantalla de bloqueo, agrega el atributo android:widgetCategory
a tu 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 tu
widget de la app en la pantalla principal. Si quieres que el widget de la app también esté disponible en la cerradura
pantalla, 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
, en el sentido de que proporciona
un diseño que pueda aparecer de inmediato hasta que se inicialice el widget de tu app y pueda actualizar el
.
Obtén más información sobre cómo crear widgets de apps para la pantalla de bloqueo, incluso para ajusta el tamaño del widget de tu 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 en un dispositivo cuenta con su propio conjunto de cuentas, aplicaciones, configuración del sistema, archivos y cualquier otro asociados con el 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 lleva un registro de qué datos del usuario pertenecen al proceso del usuario en el que que tu app se esté ejecutando y le proporcione acceso solo a los datos de ese usuario; 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 quiere identificar usuarios únicos, por ejemplo, para recopilar estadísticas o crear otra cuenta
asociaciones, 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 el otro
los problemas que introducen estos identificadores, como se explica en el artículo Cómo identificar
Entrada de blog sobre instalaciones de aplicaciones
Nueva configuración global
Se actualizó la configuración del sistema para admitir varios usuarios, además 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 es
se están realizando cambios en la configuración definida anteriormente en Settings.System
(como AIRPLANE_MODE_ON
), debes esperar que
ya no funcionará en un dispositivo con Android 4.2 o superior si esos parámetros
se movió a Settings.Global
. 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 RTL
Android ahora ofrece varias APIs que te permiten compilar interfaces de usuario que Transformar la orientación del diseño para admitir idiomas que utilizan IU de derecha a izquierda (RTL) y lectura específica, como el árabe y el hebreo.
Para comenzar a admitir diseños de derecha a izquierda en tu app, establece el atributo android:supportsRtl
en el elemento <application>
del archivo de manifiesto
y configúrala 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 RTL, 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 y 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 los archivos de diseño predeterminados enres/layout/
y tus diseños optimizados con RTL enres/layout-ldrtl/
.El calificador
ldrtl
es excelente para recursos de elementos de diseño, de modo que puedes gráficos que se orientan 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 los eventos
y en Configuration
para consultar la dirección del diseño actual.
Nota: Si usas SQlite y los nombres de las tablas o columnas son
"solo números", de
ten cuidado: usar String.format(String, Object...)
puede generar errores en los que los números
se hayan convertido a sus equivalentes árabes si el dispositivo está configurado en la configuración regional árabe.
Debes usar String.format(Locale,String,Object...)
para asegurarte de que los números estén
se conserva como ASCII. También debes usar 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 varias situaciones en
en la que colocar componentes de la IU dinámicos y reutilizables en un componente de IU que sea
dinámicos y reutilizables. 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 quieres agregar un fragmento. Se mostrará 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 dentro de un fragmento anidado, puedes obtener una referencia al fragmento superior llamando
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
fragmentos de manera 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 una secuencia de comandos intrínseca, llama al método estático
create()
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 aforEach()
. 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án con elsetInput(Script.KernelID, Allocation)
y proporcionará el resultadoAllocation
donde se escribirá el resultado y la secuencia de comandos final para se ejecuta 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 se ejecute el código resultante. 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, tu elemento Filterscript Las secuencias de comandos no deben usar tipos integrados de 32 bits y deben especificar una función raíz personalizada usando el atributo__attribute__((kernel))
porque Filterscript no admite punteros, lo cual la firma predeterminada de la funciónroot()
define.
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 API en Android 4.2, consulta la Informe de diferencias de las APIs.