Daten synchronisieren

In diesem Dokument wird beschrieben, wie Sie Daten zwischen einem Wear OS-Gerät und einem Mobilgerät synchronisieren.

Daten direkt aus dem Netzwerk senden und synchronisieren

Entwickeln Sie Wear OS-Apps, die direkt mit dem Netzwerk kommunizieren. Verwenden Sie dieselben APIs wie für die mobile Entwicklung, beachten Sie aber einige Wear OS-spezifische Unterschiede.

Daten mit der Wear OS Data Layer API synchronisieren

Ein DataClient stellt eine API für Komponenten bereit, um Daten in eine DataItem oder Asset zu lesen oder zu schreiben.

Sie können Datenelemente und Assets auch festlegen, wenn Sie mit keinem Gerät verbunden sind. Sie werden synchronisiert, wenn die Geräte eine Netzwerkverbindung herstellen. Diese Daten sind nur für Ihre App verfügbar und können nur von Ihrer App auf anderen Geräten abgerufen werden.

  • Eine DataItem wird auf allen Geräten in einem Wear OS-Netzwerk synchronisiert. Sie sind in der Regel klein.

  • Verwenden Sie ein Asset, um ein größeres Objekt wie ein Bild zu übertragen. Das System überwacht, welche Assets bereits übertragen wurden, und führt automatisch eine Deduplizierung durch.

Auf Ereignisse in Diensten warten

Erweitern Sie die Klasse WearableListenerService. Das System verwaltet den Lebenszyklus der Basis WearableListenerService und bindet sie an den Dienst, wenn Datenelemente oder Nachrichten gesendet werden müssen, und trennt die Bindung, wenn keine Arbeit erforderlich ist.

Auf Ereignisse in Aktivitäten warten

Implementieren Sie die OnDataChangedListener-Schnittstelle. Verwenden Sie diese Schnittstelle anstelle einer WearableListenerService, wenn Sie nur dann nach Änderungen suchen möchten, wenn der Nutzer Ihre App aktiv nutzt.

Daten übertragen

Wenn Sie Binary Large Objects über den Bluetooth-Transport senden möchten, z. B. eine Sprachaufnahme von einem anderen Gerät, können Sie einem Datenelement ein Asset anhängen und es dann in den replizierten Datenspeicher einfügen.

Assets übernehmen automatisch das Caching von Daten, um eine erneute Übertragung zu verhindern und die Bluetooth-Bandbreite zu schonen. Ein gängiges Muster ist, dass eine App für Mobilgeräte ein Bild herunterlädt, es auf eine für die Anzeige auf dem Wearable geeignete Größe verkleinert und es als Asset an die Wearable-App überträgt. Die folgenden Beispiele veranschaulichen dieses Muster.

Hinweis:Die Größe von Datenelementen ist zwar theoretisch auf 100 KB begrenzt, in der Praxis können jedoch auch größere Datenelemente verwendet werden. Trennen Sie größere Datenelemente nach eindeutigen Pfaden und verwenden Sie nicht einen einzigen Pfad für alle Daten. Das Übertragen großer Assets wirkt sich in vielen Fällen auf die Nutzerfreundlichkeit aus. Testen Sie daher Ihre Apps, um sicherzustellen, dass sie beim Übertragen großer Assets eine gute Leistung erzielen.

Asset übertragen

Erstelle das Asset mit einer der create...()-Methoden in der Klasse Asset. Konvertieren Sie eine Bitmap in einen Bytestream und rufen Sie dann createFromBytes() auf, um das Asset zu erstellen, wie im folgenden Beispiel gezeigt.

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());
}

Fügen Sie das Asset dann mit der putAsset()-Methode in DataMap oder PutDataRequest einem Datenelement hinzu. Fügen Sie das Datenelement dann mit der Methode putDataItem() in den Datenspeicher ein, wie in den folgenden Beispielen gezeigt.

Im folgenden Beispiel wird PutDataRequest verwendet:

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);

Im folgenden Beispiel wird PutDataMapRequest verwendet:

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);

Assets empfangen

Wenn ein Asset erstellt wird, möchten Sie es wahrscheinlich auf der anderen Seite der Verbindung lesen und extrahieren. Hier ist ein Beispiel für die Implementierung des Callbacks, um eine Asset-Änderung zu erkennen und das Asset zu extrahieren:

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);
}

Weitere Informationen finden Sie im Beispielprojekt „DataLayer“ auf GitHub.