Cómo mostrar actualizaciones dinámicas en tarjetas
Organiza tus páginas con colecciones
Guarda y categoriza el contenido según tus preferencias.
A partir de Tiles 1.2, puedes transmitir actualizaciones de datos de la plataforma usando expresiones dinámicas. Luego, puedes asociar esas actualizaciones con animaciones en tus tarjetas. Tu app recibe actualizaciones de este valor cada segundo.
Con las expresiones dinámicas, no necesitas actualizar toda la tarjeta cuando cambia su contenido. Para crear una experiencia más atractiva en tus tarjetas, anima esos objetos dinámicos.
Cómo asociar expresiones dinámicas con fuentes de datos
Los espacios de nombres androidx.wear.protolayout y androidx.wear.protolayout.material contienen muchas clases cuyos campos aceptan expresiones dinámicas.
Entre los ejemplos, se incluyen los siguientes:
Si deseas usar una expresión dinámica como un valor posible para un elemento de tu tarjeta, usa el tipo de propiedad dinámica *Prop correspondiente del elemento y pasa la fuente de datos al método setDynamicValue() de la clase de compilador del tipo de propiedad dinámica.
Las tarjetas admiten los siguientes tipos de propiedades dinámicas:
Para las dimensiones lineales, medidas en píxeles independientes de la pantalla, usa DimensionBuilders.DpProp.
Cuando usas una expresión dinámica que afecta las dimensiones físicas (cualquier valor en una tarjeta, excepto el color), también debes especificar un conjunto de restricciones relacionadas, como un formato de cadena. Estas restricciones permiten que el procesador del sistema determine la cantidad máxima de espacio que un valor podría ocupar en tu tarjeta. Por lo general, debes especificar estas restricciones a nivel del elemento, no a nivel de la expresión dinámica, llamando a un método que comience con setLayoutConstraintsForDynamic*.
En el siguiente fragmento de código, se indica cómo mostrar las actualizaciones de una frecuencia cardíaca usando 3 dígitos, con un valor de resguardo de --:
Cómo usar una pequeña cantidad de expresiones en una sola tarjeta
Wear OS establece un límite para la cantidad de expresiones que puede tener una sola tarjeta. Si una tarjeta contiene demasiadas expresiones dinámicas en total, se ignoran los valores dinámicos y el sistema recurre a los valores estáticos que proporcionas a los tipos de propiedades dinámicas respectivos.
Cómo consolidar datos dinámicos en un objeto de estado
Puedes consolidar el conjunto más reciente de actualizaciones de fuentes de datos en un estado, el cual pasas a tu tarjeta para la renderización de valores.
Para usar información de estado en tus tarjetas, realiza estos pasos:
Establece un conjunto de claves que representen los diferentes valores del estado de tu tarjeta. En este ejemplo, se crean claves para el consumo de agua y una nota:
En tu implementación de onTileRequest(), llama a setState() y establece asignaciones iniciales de cada clave a un valor de datos dinámico en particular:
Kotlin
overridefunonTileRequest(requestParams:TileRequest):ListenableFuture<Tile>{valstate=State.Builder().addKeyToValueMapping(KEY_WATER_INTAKE,DynamicDataBuilders.DynamicDataValue.fromInt(200)).addKeyToValueMapping(KEY_NOTE,DynamicDataBuilders.DynamicDataValue.fromString("Note about day")).build()// ...returnFutures.immediateFuture(Tile.Builder()// Set resources, timeline, and other tile properties..setState(state).build())
Java
@OverrideprotectedListenableFuture<Tile>onTileRequest(ListenableFuture<Tile>{Statestate=newState.Builder().addKeyToValueMapping(KEY_WATER_INTAKE,DynamicDataBuilders.DynamicDataValue.fromInt(200)).addKeyToValueMapping(KEY_NOTE,DynamicDataBuilders.DynamicDataValue.fromString("Note about day")).build();// ...returnFutures.immediateFuture(Tile.Builder()// Set resources, timeline, and other tile properties..setState(state).build());}
Cuando crees tu diseño, en un lugar en el que desees mostrar estos datos de estado, usa un objeto de tipo Dynamic*. También puedes llamar a animate() para mostrar una animación del valor anterior al valor actual:
Kotlin
DynamicInt32.from(KEY_WATER_INTAKE).animate()
Java
DynamicInt32.from(KEY_WATER_INTAKE).animate();
Cuando sea necesario, también puedes actualizar el estado con valores nuevos. Puede ser parte del elemento LoadAction de una tarjeta.
En este ejemplo, el valor de consumo de agua se actualiza a 400:
El contenido y las muestras de código que aparecen en esta página están sujetas a las licencias que se describen en la Licencia de Contenido. Java y OpenJDK son marcas registradas de Oracle o sus afiliados.
Última actualización: 2025-08-30 (UTC)
[[["Fácil de comprender","easyToUnderstand","thumb-up"],["Resolvió mi problema","solvedMyProblem","thumb-up"],["Otro","otherUp","thumb-up"]],[["Falta la información que necesito","missingTheInformationINeed","thumb-down"],["Muy complicado o demasiados pasos","tooComplicatedTooManySteps","thumb-down"],["Desactualizado","outOfDate","thumb-down"],["Problema de traducción","translationIssue","thumb-down"],["Problema con las muestras o los códigos","samplesCodeIssue","thumb-down"],["Otro","otherDown","thumb-down"]],["Última actualización: 2025-08-30 (UTC)"],[],[],null,["Starting in Tiles 1.2, you can stream platform data updates using\n[dynamic expressions](/training/wearables/data/dynamic). You can then associate these updates with animations\nin your tiles. Your app gets updates to this value every second.\n\nUsing dynamic expressions, you don't need to refresh the entire tile when its\ncontent changes. To create a more engaging experience in your tiles, animate\nthose dynamic objects.\n\nAssociate dynamic expressions with data sources\n\nThe `androidx.wear.protolayout` and `androidx.wear.protolayout.material`\nnamespaces contain many classes whose fields accept dynamic expressions.\nSeveral examples include the following:\n\n- Several length values, including the [length of an `Arc` object](/reference/androidx/wear/protolayout/LayoutElementBuilders.ArcLine#getLength()) and the [length of a `CircularProgressIndicator`](/reference/androidx/wear/protolayout/material/CircularProgressIndicator#getProgress()) object.\n- Any color, such as the [content color of a `Button` object](/reference/androidx/wear/protolayout/material/ButtonColors#getContentColor()).\n- Many string values, including the [content of a `Text` object](/reference/androidx/wear/protolayout/material/Text#getText()), the [content of a `LayoutElementsBuilders.Text` object](/reference/androidx/wear/protolayout/LayoutElementBuilders.Text#getText()), and the [content\n description of a `CircularProgressIndicator` object](/reference/androidx/wear/protolayout/material/CircularProgressIndicator#getContentDescription()).\n\nTo use a dynamic expression as a possible value for an element in your tile, use\nthe element's corresponding `*Prop` dynamic property type and pass in the data\nsource to the dynamic property type's builder class's `setDynamicValue()`\nmethod.\n\nTiles support these dynamic property types:\n\n- For linear dimensions, measured in display-independent pixels, use [`DimensionBuilders.DpProp`](/reference/androidx/wear/tiles/DimensionBuilders.DpProp).\n- For angular dimensions, measured in degrees, use [`DimensionBuilders.DegreesProp`](/reference/androidx/wear/tiles/DimensionBuilders.DegreesProp).\n- For string values, use [`TypeBuilders.StringProp`](/reference/androidx/wear/protolayout/TypeBuilders.StringProp).\n- For color values, use [`ColorBuilders.ColorProp`](/reference/androidx/wear/protolayout/ColorBuilders.ColorProp).\n- For floating-point values, use [`TypeBuilders.FloatProp`](/reference/androidx/wear/protolayout/TypeBuilders.FloatProp).\n\nWhen you use a dynamic expression that affects physical dimensions---any value in\na tile except for color---you must also specify a set of related constraints, such\nas a string format. These constraints allow the system renderer to determine the\nmaximum amount of space that a value could occupy within your tile. Usually, you\nspecify these constraints at the element level, not at the dynamic expression\nlevel, by calling a method that starts with `setLayoutConstraintsForDynamic*`.\n| **Note:** The Material components set these layout constraints automatically.\n\nThe following code snippet shows how to display updates to a heart rate using 3\ndigits, with a fallback value of `--`: \n\n```kotlin\noverride fun onTileRequest(requestParams: RequestBuilders.TileRequest) =\n Futures.immediateFuture(\n Tile.Builder()\n .setResourcesVersion(RESOURCES_VERSION)\n .setFreshnessIntervalMillis(60 * 60 * 1000) // 60 minutes\n .setTileTimeline(\n Timeline.fromLayoutElement(\n Text.Builder(\n this,\n TypeBuilders.StringProp.Builder(\"--\")\n .setDynamicValue(\n PlatformHealthSources.heartRateBpm()\n .format()\n .concat(DynamicBuilders.DynamicString.constant(\" bpm\"))\n )\n .build(),\n TypeBuilders.StringLayoutConstraint.Builder(\"000\").build(),\n )\n .build()\n )\n )\n .build()\n )https://github.com/android/snippets/blob/f95ab59fad80aeaf5d6a90bab8a01a126f20f44e/wear/src/main/java/com/example/wear/snippets/tile/Tile.kt#L178-L200\n```\n\nUse a small number of expressions within a single tile\n\nWear OS [places a limit](/training/wearables/data/dynamic#use-limited-number-per-screen) on the number of expressions that a single tile can\nhave. If a tile contains too many total dynamic expressions, dynamic values are\nignored, and the system falls back to the static values that you provide to the\nrespective dynamic property types.\n\nConsolidate dynamic data into a state object\n\nYou can consolidate the latest set of updates from data sources into a *state*,\nwhich you pass over to your tile for value rendering.\n\nTo use state information in your tiles, complete these steps:\n\n1. Establish a set of keys that represent the different values of your tile's\n state. This example creates keys for water intake and a note:\n\n Kotlin \n\n ```kotlin\n companion object {\n val KEY_WATER_INTAKE = AppDataKey\u003cDynamicInt32\u003e(\"water_intake\")\n val KEY_NOTE = AppDataKey\u003cDynamicString\u003e(\"note\")\n }\n ```\n\n Java \n\n ```java\n private static final AppDataKey\u003cDynamicInt32\u003e KEY_WATER_INTAKE =\n new AppDataKey\u003cDynamicInt32\u003e(\"water_intake\");\n private static final AppDataKey\u003cDynamicString\u003e KEY_NOTE =\n new AppDataKey\u003cDynamicString\u003e(\"note\");\n ```\n2. In your implementation of `onTileRequest()`, call `setState()` and establish\n initial mappings from each key to a particular dynamic data value:\n\n Kotlin \n\n ```kotlin\n override fun onTileRequest(requestParams: TileRequest):\n ListenableFuture\u003cTile\u003e {\n val state = State.Builder()\n .addKeyToValueMapping(KEY_WATER_INTAKE,\n DynamicDataBuilders.DynamicDataValue.fromInt(200))\n .addKeyToValueMapping(KEY_NOTE,\n DynamicDataBuilders.DynamicDataValue.fromString(\"Note about day\"))\n .build()\n // ...\n\n return Futures.immediateFuture(Tile.Builder()\n // Set resources, timeline, and other tile properties.\n .setState(state)\n .build()\n )\n ```\n\n Java \n\n ```java\n @Override\n protected ListenableFuture\u003cTile\u003e onTileRequest(\n ListenableFuture\u003cTile\u003e {\n State state = new State.Builder()\n .addKeyToValueMapping(KEY_WATER_INTAKE,\n DynamicDataBuilders.DynamicDataValue.fromInt(200))\n .addKeyToValueMapping(KEY_NOTE,\n DynamicDataBuilders.DynamicDataValue.fromString(\"Note about day\"))\n .build();\n // ...\n\n return Futures.immediateFuture(Tile.Builder()\n // Set resources, timeline, and other tile properties.\n .setState(state)\n .build()\n );\n }\n ```\n3. When you create your layout, in a place where you want to show this data\n from state, use a `Dynamic*` type object. You can also call `animate()` to\n show an animation from the previous value to the current value:\n\n Kotlin \n\n ```kotlin\n DynamicInt32.from(KEY_WATER_INTAKE).animate()\n ```\n\n Java \n\n ```java\n DynamicInt32.from(KEY_WATER_INTAKE).animate();\n ```\n4. When needed, you can also update the state with new values. This can be\n part of a tile's [`LoadAction`](/reference/androidx/wear/protolayout/ActionBuilders.LoadAction).\n\n In this example, the water intake value is updated to `400`: \n\n Kotlin \n\n ```kotlin\n val loadAction = LoadAction.Builder()\n .setRequestState(\n State.Builder()\n .addKeyToValueMapping(\n KEY_WATER_INTAKE,\n DynamicDataBuilders.DynamicDataValue.fromInt(400)\n )\n .build()\n )\n .build()\n ```\n\n Java \n\n ```java\n LoadAction loadAction = new LoadAction.Builder()\n .setRequestState(\n new State.Builder()\n .addKeyToValueMapping(\n KEY_WATER_INTAKE,\n DynamicDataBuilders.DynamicDataValue.fromInt(400)\n ).build()\n ).build();\n ```\n\nRecommended for you\n\n- Note: link text is displayed when JavaScript is off\n- [Migrate to ProtoLayout namespaces](/training/wearables/tiles/migrate-to-protolayout)\n- [Get started with tiles](/training/wearables/tiles/get_started)\n- [Other considerations](/develop/ui/compose/migrate/other-considerations)"]]