Questo documento descrive come sincronizzare i dati tra un dispositivo Wear OS e un dispositivo palmare.
Invia e sincronizza i dati direttamente dalla rete
Crea app per 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 risorse senza essere connessi a nessun dispositivo. Vengono sincronizzati quando i dispositivi stabiliscono una connessione di rete. Questi dati sono privati della 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. Sono generalmente 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 automaticamente la deduplica.
Ascolta gli eventi nei servizi
Espandi la classe WearableListenerService
. Il sistema gestisce il ciclo di vita della base WearableListenerService
, eseguendo il binding al servizio quando deve inviare elementi di dati o messaggi e sganciando il servizio quando non è necessario alcun intervento.
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 di grandi dimensioni binari tramite il trasporto Bluetooth, ad esempio una registrazione vocale da un altro dispositivo, puoi allegare un
Asset
a un elemento dati e poi inserire l'elemento dati nel data store replicato.
Le risorse gestiscono automaticamente la memorizzazione nella cache dei dati per evitare la ritrasmissione e per risparmiare larghezza di banda Bluetooth. Un pattern comune è che un'app per dispositivi mobili scarichi un'immagine, la riduca a dimensioni appropriate per la visualizzazione sul dispositivo indossabile e la trasmetta all'app come asset. Gli esempi riportati di seguito illustrano questo pattern.
Nota:anche se la dimensione degli elementi dati è teoricamente limitata a 100 KB, in pratica è possibile utilizzare elementi dati più grandi. Per gli elementi di dati più grandi, separa i dati in base a percorsi univoci 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 bene durante il trasferimento di asset di grandi dimensioni.
Trasferire una risorsa
Crea la risorsa utilizzando uno dei metodi create...()
della classe
Asset
.
Converti un bitmap in uno stream di byte e poi chiama
createFromBytes()
per creare l'asset, come mostrato nell'esempio seguente.
private fun createAssetFromBitmap(bitmap: Bitmap): Asset = ByteArrayOutputStream().let { byteStream -> bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteStream) Asset.createFromBytes(byteStream.toByteArray()) }
private static Asset createAssetFromBitmap(Bitmap bitmap) { final ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteStream); return Asset.createFromBytes(byteStream.toByteArray()); }
Successivamente, collega l'asset a un elemento dati con il metodo putAsset()
in
DataMap
o
PutDataRequest
. Poi inserisci l'elemento dati nel datastore utilizzando il metodo
putDataItem()
, come mostrato negli esempi riportati di seguito.
L'esempio seguente utilizza PutDataRequest
:
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)
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
:
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)
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 creata una risorsa, probabilmente vuoi leggerla ed estrarla dall'altro lato della connessione. Ecco un esempio di come implementare il callback per rilevare una modifica dell'asset ed estrarlo:
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 } }
@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.