Synchroniser les données persistantes

Ce document explique comment synchroniser des données entre un appareil Wear OS et un portable.

Envoyer et synchroniser des données directement à partir du réseau

Créez des applications Wear OS pour communiquer directement avec le réseau. Utiliser la même les API que vous utilisez pour le développement mobile, mais qui conservent des exigences spécifiques à Wear OS ; à l'esprit les différences.

Synchroniser des données à l'aide de l'API Wear OS Data Layer

Un DataClient expose une API pour que les composants puissent lire ou écrire dans un DataItem ou Asset

Il est possible de définir des éléments de données et des éléments sans être connecté à aucun appareil. Ils sont synchronisés lorsque les appareils établissent une connexion réseau. Ces données est privée et n'est accessible qu'à votre application sur d'autres appareils.

  • Un DataItem est synchronisé sur tous les appareils d'un réseau Wear OS. Ils sont généralement de petite taille.

  • Utilisez un Asset pour transférer un objet plus volumineux, comme une image. Le système effectue le suivi des éléments qui ont déjà été transférés et effectue automatiquement la déduplication.

Écouter les événements dans les services

Étendez la classe WearableListenerService. Le système gère cycle de vie du WearableListenerService de base, qui est lié au service doit envoyer des éléments de données ou des messages et annuler le lien avec le service en l'absence de travail nécessaires.

Écouter les événements dans les activités

Implémentez l'interface OnDataChangedListener. Utilisez plutôt cette interface d'un WearableListenerService lorsque vous souhaitez écouter les modifications uniquement lorsque utilise activement votre application.

Transférer des données

Pour envoyer des objets binaires volumineux via le transport Bluetooth, tels qu'un enregistrement vocal depuis un autre appareil, vous pouvez connecter Asset à un élément de données, puis placer cet élément dans le datastore répliqué.

Les éléments gèrent automatiquement la mise en cache des données pour empêcher la retransmission et préserver la bande passante Bluetooth. Il est courant de télécharger une image, de la réduire à une taille appropriée pour l'afficher sur l'objet connecté et de la transmettre à l'application connectée en tant qu'élément. Les exemples suivants illustrent ce schéma.

Remarque : Bien que la taille des éléments de données soit théoriquement limitée à 100 Ko, en pratique, vous pouvez utiliser des éléments de données plus volumineux. Pour les éléments de données plus volumineux, séparez les données par des chemins uniques et éviter d'utiliser un seul chemin pour toutes les données. Dans de nombreux cas, le transfert d'éléments volumineux affecte l'expérience utilisateur. Par conséquent, testez vos applications pour vous assurer qu'elles fonctionnent bien lors de ce type de transfert.

Transférer un élément

Créez l'élément à l'aide de l'une des méthodes create...() de la classe Asset. Convertissez un bitmap en flux d'octets, puis appelez createFromBytes() pour créer l'élément, comme illustré dans l'exemple suivant.

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

Associez ensuite cet élément à un élément de données avec la méthode putAsset() dans DataMap ou PutDataRequest. Placez ensuite l'élément de données dans le magasin de données à l'aide de la méthode putDataItem(), comme illustré dans les exemples suivants.

L'exemple suivant utilise 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'exemple suivant utilise 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);

Recevoir les éléments

Lorsqu'un élément est créé, vous souhaitez probablement le lire et l'extraire de l'autre côté de la connexion. Voici un exemple d'implémentation du rappel pour détecter une modification d'élément et l'extraire :

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

Pour en savoir plus, consultez l'exemple de projet DataLayer sur GitHub.