Sincronizza i dati permanenti

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 per Wear OS per comunicare direttamente con la rete. Usa lo stesso API che utilizzi per lo sviluppo mobile, ma che mantengono alcune specifiche per Wear OS le differenze esistenti.

Sincronizzare i dati utilizzando l'API Data Layer di Wear OS

Un DataClient espone un'API per consentire ai componenti di leggere o scrivere su un DataItem o Asset.

Puoi impostare elementi di dati e asset senza connessione a nessun dispositivo. Vengono sincronizzati quando i dispositivi stabiliscono una connessione di rete. Questi dati è privata per la tua app ed è accessibile all'app soltanto su altri dispositivi.

  • Viene sincronizzato un DataItem su tutti i dispositivi di una rete Wear OS. Di solito sono di dimensioni ridotte.

  • Usa un Asset per trasferire un oggetto più grande, ad esempio un'immagine. Il sistema tiene traccia delle risorse già trasferite e delle loro prestazioni la deduplicazione automatica.

Ascolta gli eventi nei servizi

Estendi il corso WearableListenerService. Il sistema gestisce ciclo di vita di base WearableListenerService, associato al servizio quando deve inviare elementi di dati o messaggi e annullare l'associazione del servizio quando non è necessaria.

Ascolta gli eventi nelle attività

Implementa l'interfaccia di OnDataChangedListener. Utilizza questa interfaccia di WearableListenerService quando vuoi ascoltare le modifiche solo quando che l'utente sta utilizzando attivamente la tua app.

Trasferisci dati

Inviare oggetti binari di grandi dimensioni tramite il trasporto Bluetooth, ad esempio una registrazione vocale da un altro dispositivo, puoi collegare Asset a un elemento di dati e quindi inserirlo nel datastore replicato.

Gli asset gestiscono automaticamente la memorizzazione nella cache dei dati per impedire la ritrasmissione e per risparmiare larghezza di banda Bluetooth. Un modello comune è che un'app portatile scarichi un'immagine e la riduca a dimensioni appropriate per la visualizzazione sul dispositivo indossabile e lo trasmette all'app indossabile come risorsa. I seguenti esempi dimostrano questo pattern.

Nota: anche se la dimensione degli elementi di dati è teoricamente limitata a 100 kB, in pratica è possibile utilizzare elementi di dati più grandi. Per più grandi, separa i dati in base a percorsi unici ed evita utilizzando un unico percorso per tutti i dati. Il trasferimento di risorse di grandi dimensioni influisce sull'esperienza utente in molti in altri casi, ti consigliamo di testare le app per assicurarti che funzionino correttamente quando trasferisci risorse di grandi dimensioni.

Trasferire una risorsa

Crea l'asset utilizzando uno dei create...() metodi nella sezione Asset. Converti una bitmap in un flusso di byte e quindi richiama createFromBytes() per creare l'asset, come illustrato 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());
}

Successivamente, collega l'asset a un elemento dati con il metodo putAsset() DataMap oppure PutDataRequest. Quindi, inserisci l'elemento dati nel datastore utilizzando putDataItem(), come mostrato negli esempi riportati di seguito.

Il seguente esempio 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);

Il seguente esempio 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);

Ricevi asset

Quando viene creato un asset, probabilmente vorrai leggere ed estrarre dall'altro lato della connessione. Di seguito viene riportato un esempio di come implementare per rilevare una modifica apportata all'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 la sezione Progetto di esempio Datalayer su GitHub.