Synchroniser des éléments de données avec l'API Data Layer

Un élément DataItem définit l'interface que le système utilise pour synchroniser les données entre les éléments portables et connectés. Un élément DataItem comprend généralement les composants suivants :

  • Charge utile : tableau d'octets que vous pouvez définir à l'aide de données et qui vous permet de sérialiser et de désérialiser vos propres objets. La taille de la charge utile est limitée à 100 Ko.
  • Chemin : chaîne unique qui doit commencer par une barre oblique, telle que "/path/to/data".

Remarque : L'API Data Layer ne peut envoyer des messages et synchroniser des données qu'avec des téléphones Android ou des montres Wear OS. Si votre appareil Wear OS est associé à un appareil iOS, l'API Data Layer ne fonctionnera pas.

Pour cette raison, n'utilisez pas l'API Data Layer comme moyen principal de communication avec un réseau. Suivez plutôt le même schéma dans votre application Wear que dans une application mobile, avec quelques différences mineures.

Normalement, vous n'intégrez pas DataItem directement. Procédez plutôt comme suit :

  1. Créez un objet PutDataRequest en précisant un chemin de chaîne pour identifier exclusivement l'élément.
  2. Appelez setData() pour définir la charge utile.
  3. Si un retard de synchronisation nuit à l'expérience utilisateur, appelez setUrgent().
  4. Utilisez la méthode putDataItem de la classe DataClient pour demander au système de créer l'élément de données.

Lorsque vous demandez des éléments de données, le système renvoie des objets qui intègrent correctement l'interface DataItem. Toutefois, au lieu d'utiliser des octets bruts à l'aide de setData(), nous vous recommandons d'utiliser un mappage de données, qui expose un élément de données avec une interface de type Bundle.

Pour en savoir plus, consultez l'exemple DataLayer.

Synchroniser des données avec un mappage de données

Si possible, utilisez la classe DataMap. Cette approche vous permet d'utiliser des éléments de données sous la forme d'un élément Bundle Android, afin que le système effectue la sérialisation et la désérialisation des objets à votre place. Vous pouvez également manipuler des données à l'aide de paires clé/valeur.

Pour utiliser un mappage de données :

  1. Créez un objet PutDataMapRequest en définissant le chemin d'accès à l'élément de données.

    Remarque : La chaîne de chemin d'accès est un identifiant unique associé à l'élément de données. Il vous permet d'y accéder de chaque côté de la connexion. Le chemin doit commencer par une barre oblique. Si vous utilisez des données hiérarchiques dans votre application, créez un schéma de chemin d'accès correspondant à la structure des données.

  2. Appelez PutDataMapRequest.getDataMap() pour obtenir un mappage de données sur lequel vous pouvez définir des valeurs.
  3. Définissez des valeurs pour le mappage de données à l'aide des méthodes put...(), telles que putString().
  4. Si un retard de synchronisation nuit à l'expérience utilisateur, appelez setUrgent().
  5. Appelez PutDataMapRequest.asPutDataRequest() pour obtenir un objet PutDataRequest.
  6. Utilisez la méthode putDataItem de la classe DataClient pour demander au système de créer l'élément de données.

    Remarque : Si le téléphone et les accessoires connectés sont déconnectés, les données sont mises en mémoire tampon et synchronisées une fois la connexion rétablie.

Dans l'exemple suivant, la méthode increaseCounter() montre comment créer un mappage de données et y insérer des données :

Kotlin

private const val COUNT_KEY = "com.example.key.count"

class MainActivity : Activity() {

    private lateinit var dataClient: DataClient
    private var count = 0
    ...
    // Create a data map and put data in it
    private fun increaseCounter() {
        val putDataReq: PutDataRequest = PutDataMapRequest.create("/count").run {
            dataMap.putInt(COUNT_KEY, count++)
            asPutDataRequest()
        }
        val putDataTask: Task<DataItem> = dataClient.putDataItem(putDataReq)
    }
    ...
}

Java

public class MainActivity extends Activity {
    private static final String COUNT_KEY = "com.example.key.count";
    private DataClient dataClient;
    private int count = 0;
    ...
    // Create a data map and put data in it
    private void increaseCounter() {
        PutDataMapRequest putDataMapReq = PutDataMapRequest.create("/count");
        putDataMapReq.getDataMap().putInt(COUNT_KEY, count++);
        PutDataRequest putDataReq = putDataMapReq.asPutDataRequest();
        Task<DataItem> putDataTask = dataClient.putDataItem(putDataReq);
    }
  ...
}

Pour en savoir plus sur la gestion de Tasks, consultez les documents de référence.

Définir la priorité de DataItem

L'API DataClient autorise les requêtes urgentes de synchronisation des objets DataItem. Normalement, le système retarde la diffusion des éléments de données sur le réseau Wear OS afin d'améliorer l'autonomie de la batterie des appareils des utilisateurs. Toutefois, si un retard dans la synchronisation des éléments de données nuit à l'expérience utilisateur, vous pouvez les marquer comme urgents. Par exemple, dans une application de commande à distance où l'utilisateur s'attend à ce que ses actions aient des effets immédiats, vous pouvez configurer le système pour synchroniser vos éléments de données en appelant setUrgent().

Si vous n'appelez pas setUrgent(), le système peut mettre jusqu'à 30 minutes avant de synchroniser les éléments de données non urgents. En général, ce délai ne dépasse toutefois pas quelques minutes. Le caractère d'urgence est défini par défaut comme non urgent. Vous devez donc utiliser setUrgent() si vous devez conserver le comportement de synchronisation immédiate des versions précédentes de l'API Wear OS.

Écouter les événements d'éléments de données

Si un côté de la connexion de la couche de données modifie un élément de données, signalez à l'utilisateur toute modification de l'autre côté de la connexion. Pour ce faire, intégrez un écouteur pour les événements d'éléments de données.

Dans l'exemple suivant, l'extrait de code avertit l'application lorsque la valeur du compteur défini dans l'exemple précédent change :

Kotlin

private const val COUNT_KEY = "com.example.key.count"

class MainActivity : Activity(), DataClient.OnDataChangedListener {

    private var count = 0

    override fun onResume() {
        super.onResume()
        Wearable.getDataClient(this).addListener(this)
    }

    override fun onPause() {
        super.onPause()
        Wearable.getDataClient(this).removeListener(this)
    }

    override fun onDataChanged(dataEvents: DataEventBuffer) {
        dataEvents.forEach { event ->
            // DataItem changed
            if (event.type == DataEvent.TYPE_CHANGED) {
                event.dataItem.also { item ->
                    if (item.uri.path.compareTo("/count") == 0) {
                        DataMapItem.fromDataItem(item).dataMap.apply {
                            updateCount(getInt(COUNT_KEY))
                        }
                    }
                }
            } else if (event.type == DataEvent.TYPE_DELETED) {
                // DataItem deleted
            }
        }
    }

    // Method to update the count
    private fun updateCount(int: Int) { ... }
    ...
}

Java

public class MainActivity extends Activity implements DataClient.OnDataChangedListener {
    private static final String COUNT_KEY = "com.example.key.count";
    private int count = 0;

    @Override
    protected void onResume() {
        super.onResume();
        Wearable.getDataClient(this).addListener(this);
    }

    @Override
    protected void onPause() {
        super.onPause();
        Wearable.getDataClient(this).removeListener(this);
    }

    @Override
    public void onDataChanged(DataEventBuffer dataEvents) {
        for (DataEvent event : dataEvents) {
            if (event.getType() == DataEvent.TYPE_CHANGED) {
                // DataItem changed
                DataItem item = event.getDataItem();
                if (item.getUri().getPath().compareTo("/count") == 0) {
                    DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap();
                    updateCount(dataMap.getInt(COUNT_KEY));
                }
            } else if (event.getType() == DataEvent.TYPE_DELETED) {
                // DataItem deleted
            }
        }
    }

    // Method to update the count
    private void updateCount(int c) { ... }
    ...
}

Cette activité intègre l'interface DataClient.OnDataChangedListener. L'activité s'ajoute en tant qu'écouteur pour les événements d'éléments de données dans la méthode onResume() et supprime l'écouteur dans la méthode onPause(). Pour voir une implémentation à l'aide d'images, de modèles de vues et de services, consultez l'exemple d'application DataLayer.

Vous pouvez également intégrer l'écouteur en tant que service. Pour en savoir plus, consultez Écouter les événements de la couche de données.