Questo documento descrive come sincronizzare i dati tra un dispositivo Wear OS e un dispositivo portatile.
Invia e sincronizza i dati direttamente dalla rete
Crea app Wear OS per comunicare direttamente con la rete. Utilizza le stesse API che usi per lo sviluppo mobile, ma tieni presente alcune differenze specifiche di Wear OS.
Sincronizzare i dati utilizzando l'API Wear OS Data Layer
Un DataClient
espone un'API per consentire ai componenti di leggere o scrivere in un DataItem
o
Asset
.
È possibile impostare elementi di dati e asset senza essere connessi a dispositivi. Vengono sincronizzati quando i dispositivi stabiliscono una connessione di rete. Questi dati sono privati per la tua app e sono accessibili solo alla tua app su altri dispositivi.
Un
DataItem
viene sincronizzato su tutti i dispositivi di una rete Wear OS. In genere, sono di piccole dimensioni.Utilizza un
Asset
per trasferire un oggetto più grande, ad esempio un'immagine. Il sistema tiene traccia delle risorse già trasferite ed esegue la deduplicazione automaticamente.
Ascolta gli eventi nei servizi
Estendi la lezione WearableListenerService
. Il sistema gestisce il
ciclo di vita dell'WearableListenerService
di base, eseguendo il binding al servizio quando
deve inviare elementi di dati o messaggi e annullando il binding del servizio quando non è
necessario alcun lavoro.
Ascolta gli eventi nelle attività
Implementa l'interfaccia OnDataChangedListener
. Utilizza questa interfaccia anziché un WearableListenerService
quando vuoi rilevare le modifiche solo quando l'utente utilizza attivamente la tua app.
Trasferisci dati
Per inviare oggetti binari di grandi dimensioni tramite il trasporto Bluetooth, ad esempio una registrazione vocale
da un altro dispositivo, puoi allegare un
Asset
a un elemento di dati e poi inserire l'elemento di dati nel datastore replicato.
Gli asset gestiscono automaticamente la memorizzazione nella cache dei dati per evitare la ritrasmissione e per risparmiare larghezza di banda Bluetooth. Un pattern comune prevede che un'app mobile scarichi un'immagine, la ridimensioni a una dimensione appropriata per la visualizzazione sul wearable e la trasmetta all'app wearable come asset. I seguenti esempi mostrano questo pattern.
Nota:anche se le dimensioni degli elementi di dati sono teoricamente limitate a 100 KB, in pratica è possibile utilizzare elementi di dati più grandi. Per gli elementi di dati più grandi, separa i dati in base a percorsi unici ed evita di utilizzare un unico percorso per tutti i dati. Il trasferimento di asset di grandi dimensioni influisce sull'esperienza utente in molti casi, quindi testa le tue app per assicurarti che funzionino correttamente durante il trasferimento di asset di grandi dimensioni.
Trasferire un asset
Crea l'asset utilizzando uno dei metodi create...()
nella classe
Asset
.
Converti una bitmap in un flusso di byte e poi chiama
createFromBytes()
per creare l'asset, come mostrato nell'esempio seguente.
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()); }
Dopodiché, collega l'asset a un elemento di dati con il metodo putAsset()
in
DataMap
o
PutDataRequest
. Poi inserisci l'elemento di dati nel datastore utilizzando il metodo
putDataItem()
, come mostrato negli esempi seguenti.
L'esempio seguente utilizza 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);
L'esempio seguente utilizza 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);
Ricevere asset
Quando viene creato un asset, probabilmente vuoi leggerlo ed estrarlo dall'altro lato della connessione. Ecco un esempio di come implementare il callback per rilevare una modifica dell'asset ed estrarlo:
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); }
Per maggiori informazioni, consulta il progetto di esempio DataLayer su GitHub.