En este documento, se describe cómo sincronizar datos entre un dispositivo Wear OS y un dispositivo portátil.
Envía y sincroniza datos directamente desde la red
Compila apps para Wear OS para comunicarse directamente con la red. Usa la misma que usas para el desarrollo para dispositivos móviles, pero que mantienen algunas APIs diferencias en mente.
Cómo sincronizar datos con la API de Data Layer de Wear OS
Un DataClient
expone una API para que los componentes lean o escriban en un DataItem
.
Asset
Es posible configurar elementos de datos y recursos mientras no estás conectado a ningún dispositivo. Se sincronizan cuando los dispositivos establecen una conexión de red. Estos datos es privado para tu app y solo tu app puede acceder a él en otros dispositivos.
Un
DataItem
se sincroniza en todos los dispositivos de una red de Wear OS. Por lo general, son de tamaño pequeño.Usa un
Asset
para transferir un objeto más grande, como una imagen. El sistema realiza un seguimiento de los activos que ya se transfirieron y realiza la anulación de duplicación automáticamente.
Cómo detectar eventos en servicios
Extiende la clase WearableListenerService
. El sistema administra
de la WearableListenerService
base, y se vincula al servicio cuando este
necesita enviar elementos de datos o mensajes y desvincular el servicio cuando no hay trabajo
según tus necesidades.
Cómo escuchar eventos en actividades
Implementa la interfaz OnDataChangedListener
. En su lugar, usa esta interfaz
de una WearableListenerService
si deseas escuchar cambios solo cuando
el usuario usa activamente la app.
Cómo transferir datos
Para enviar objetos binarios grandes a través de Bluetooth, como una grabación de voz
desde otro dispositivo, puedes conectar un
Asset
a un elemento de datos y, luego, colocarlo en el almacén de datos replicado
Los recursos manejan automáticamente el almacenamiento en caché de datos para evitar la retransmisión y conservar el ancho de banda de Bluetooth. Un patrón común es que una app para dispositivos de mano descargue una imagen, reduzca su tamaño a uno apropiado de modo que pueda verse en el wearable y la transmita como recurso a la app para wearables. En los siguientes ejemplos, se muestra este patrón.
Nota: Aunque, en teoría, el tamaño de los elementos de datos se limita a 100 KB, en la práctica se pueden usar elementos de datos más grandes. En el caso de los elementos de datos más grandes, separa los datos por rutas de acceso únicas y evita el uso de una sola para todos los datos. La transferencia de recursos grandes afecta la experiencia del usuario en muchos casos; por ello, prueba tus apps para asegurarte de que funcionen bien si transfieres recursos grandes.
Cómo transferir un recurso
Crea el recurso usando uno de los métodos create...()
en la clase Asset
.
Convierte un mapa de bits en un flujo de bytes y, luego, llama a createFromBytes()
para crear el recurso, como se muestra en el siguiente ejemplo.
Kotlin
private fun createAssetFromBitmap(bitmap: Bitmap): Asset = ByteArrayOutputStream().let { byteStream -> bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteStream) Asset.createFromBytes(byteStream.toByteArray()) }
Java
private static Asset createAssetFromBitmap(Bitmap bitmap) { final ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteStream); return Asset.createFromBytes(byteStream.toByteArray()); }
Luego, adjunta el recurso a un elemento de datos con el método putAsset()
en DataMap
o PutDataRequest
. Luego, pon el elemento de datos en el almacén de datos con la
putDataItem()
, como se muestra en los siguientes ejemplos.
En el siguiente ejemplo, se usa PutDataRequest
:
Kotlin
val asset: Asset = BitmapFactory.decodeResource(resources, R.drawable.image).let { bitmap -> createAssetFromBitmap(bitmap) } val request: PutDataRequest = PutDataRequest.create("/image").apply { putAsset("profileImage", asset) } val putTask: Task<DataItem> = Wearable.getDataClient(context).putDataItem(request)
Java
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image); Asset asset = createAssetFromBitmap(bitmap); PutDataRequest request = PutDataRequest.create("/image"); request.putAsset("profileImage", asset); Task<DataItem> putTask = Wearable.getDataClient(context).putDataItem(request);
En el siguiente ejemplo, se usa PutDataMapRequest
:
Kotlin
val asset: Asset = BitmapFactory.decodeResource(resources, R.drawable.image).let { bitmap -> createAssetFromBitmap(bitmap) } val request: PutDataRequest = PutDataMapRequest.create("/image").run { dataMap.putAsset("profileImage", asset) asPutDataRequest() } val putTask: Task<DataItem> = Wearable.getDataClient(context).putDataItem(request)
Java
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image); Asset asset = createAssetFromBitmap(bitmap); PutDataMapRequest dataMap = PutDataMapRequest.create("/image"); dataMap.getDataMap().putAsset("profileImage", asset); PutDataRequest request = dataMap.asPutDataRequest(); Task<DataItem> putTask = Wearable.getDataClient(context).putDataItem(request);
Cómo recibir recursos
Cuando se crea un recurso, es probable que quieras leerlo y extraerlo en otro extremo de la conexión. A continuación, se incluye un ejemplo de cómo implementar la devolución de llamada para detectar un cambio de recurso y extraerlo:
Kotlin
override fun onDataChanged(dataEvents: DataEventBuffer) { dataEvents .filter { it.type == DataEvent.TYPE_CHANGED && it.dataItem.uri.path == "/image" } .forEach { event -> val bitmap: Bitmap? = DataMapItem.fromDataItem(event.dataItem) .dataMap.getAsset("profileImage") .let { asset -> loadBitmapFromAsset(asset) } // Do something with the bitmap } } fun loadBitmapFromAsset(asset: Asset): Bitmap? { // Convert asset into a file descriptor and block until it's ready val assetInputStream: InputStream? = Tasks.await(Wearable.getDataClient(context).getFdForAsset(asset)) ?.inputStream return assetInputStream?.let { inputStream -> // Decode the stream into a bitmap BitmapFactory.decodeStream(inputStream) } ?: run { Log.w(TAG, "Requested an unknown Asset.") null } }
Java
@Override public void onDataChanged(DataEventBuffer dataEvents) { for (DataEvent event : dataEvents) { if (event.getType() == DataEvent.TYPE_CHANGED && event.getDataItem().getUri().getPath().equals("/image")) { DataMapItem dataMapItem = DataMapItem.fromDataItem(event.getDataItem()); Asset profileAsset = dataMapItem.getDataMap().getAsset("profileImage"); Bitmap bitmap = loadBitmapFromAsset(profileAsset); // Do something with the bitmap } } } public Bitmap loadBitmapFromAsset(Asset asset) { if (asset == null) { throw new IllegalArgumentException("Asset must be non-null"); } // Convert asset into a file descriptor and block until it's ready InputStream assetInputStream = Tasks.await(Wearable.getDataClient(context).getFdForAsset(asset)) .getInputStream(); if (assetInputStream == null) { Log.w(TAG, "Requested an unknown Asset."); return null; } // Decode the stream into a bitmap return BitmapFactory.decodeStream(assetInputStream); }
Para obtener más información, consulta el proyecto de ejemplo de DataLayer en GitHub.