Cómo sincronizar elementos de datos en Wear

Un DataItem define la interfaz que usa el sistema para sincronizar datos entre dispositivos portátiles y wearables. En general, un DataItem tiene los siguientes componentes:

  • Carga útil: Es un arreglo de bytes que puedes configurar con los datos que quieras, lo que te permite realizar tu propia serialización o deserialización de objetos. El tamaño de la carga útil está limitado a 100 KB.
  • Ruta de acceso: Es una string única que debe comenzar con una barra diagonal (por ejemplo, "/path/to/data").

Nota: Una app para Wear puede comunicarse con una aplicación para teléfonos usando la API de Data Layer, pero no es recomendable conectarse a una red con esta API.

Por lo general, no se implementa DataItem directamente. En su lugar, haz lo siguiente:

  1. Crea un PutDataRequest y especifica una ruta de acceso de strings para identificar el elemento de forma única.
  2. Llama a setData() para configurar la carga útil.
  3. Si una demora en la sincronización perjudicara la experiencia del usuario, llama a setUrgent().
  4. Usa el método putDataItem de la clase DataClient para solicitar que el sistema cree el elemento de datos.

Al solicitar elementos de datos, el sistema mostrará objetos que implementan adecuadamente la interfaz DataItem. Sin embargo, en lugar trabajar con bytes sin procesar usando setData(), te recomendamos emplear un mapa de datos, que expone un elemento de datos con una interfaz similar a Bundle fácil de usar.

Consulta los siguientes recursos relacionados:

Cómo sincronizar datos con un mapa de datos

Cuando sea posible, usa la clase DataMap. Este enfoque te permite trabajar con elementos de datos en el formato de Bundle de Android, por lo que el sistema realiza la serialización y deserialización de objetos por ti, y puedes manipular los datos con pares clave-valor.

Para utilizar un mapa de datos, haz lo siguiente:

  1. Crea un objeto PutDataMapRequest y configura la ruta de acceso del elemento de datos.

    Nota: La string de la ruta de acceso es un identificador exclusivo para el elemento de datos que te permite acceder a él desde ambos extremos de la conexión. Esta ruta debe comenzar con una barra diagonal. Si usas datos jerárquicos en tu app, debes crear un esquema de ruta de acceso que coincida con la estructura de los datos.

  2. Llama a PutDataMapRequest.getDataMap() para obtener un mapa de datos en el que puedas establecer valores.
  3. Define los valores que desees para el mapa de datos usando los métodos put...(), como putString().
  4. Si una demora en la sincronización perjudica la experiencia del usuario, llama a setUrgent().
  5. Llama a PutDataMapRequest.asPutDataRequest() para obtener un objeto PutDataRequest.
  6. Usa el método putDataItem de la clase DataClient para solicitar que el sistema cree el elemento de datos.

    Nota: Si el dispositivo portátil y el wearable están desconectados, se almacenan los datos en búfer y se sincronizan cuando se restablece la conexión.

El método increaseCounter() del siguiente ejemplo muestra cómo crear un mapa de datos y agregarle datos:

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

Para obtener más información sobre el manejo de Tasks, consulta la documentación de referencia.

Cómo establecer la prioridad de DataItem

La API de DataClient admite solicitudes urgentes en la sincronización de DataItems. Por lo general, el sistema puede retrasar la publicación de DataItems en la red de Wear para extender la duración de batería de los dispositivos del usuario, pero si una demora en la sincronización de DataItems perjudica la experiencia del usuario, puedes marcarlos como urgente. Por ejemplo, en el caso de una app de control remoto en la que el usuario espera que se reflejen inmediatamente sus acciones, puedes hacer que el sistema sincronice al instante tus DataItems si llamas a setUrgent().

Si no llamas a setUrgent(), el sistema puede demorar hasta 30 minutos en sincronizar los DataItems no urgentes. No obstante, puedes esperar que la demora sea de unos minutos, si es que se produce. La urgencia predeterminada ahora es "no urgente", por lo que debes usar setUrgent() si quieres conservar el comportamiento de sincronización inmediata presente en versiones anteriores de la API de Wear.

Cómo escuchar eventos de elementos de datos

Si un extremo de la conexión de Data Layer modifica un elemento de datos, es probable que quieras recibir notificaciones sobre cambios en el otro extremo de la conexión. Puedes lograrlo si implementas un objeto de escucha para eventos de elementos de datos.

El fragmento de código en el siguiente ejemplo notifica a tu app cuando cambia el valor del contador definido en el ejemplo anterior:

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

        // Our 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
                }
            }
        }

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

        ...
    }
    

Esta actividad implementa la interfaz DataClient.OnDataChangedListener. Además, se agrega a sí misma como objeto de escucha para eventos de elementos de datos dentro del método onResume() y quita el elemento de escucha en el método onPause().

También puedes implementar el objeto de escucha como un servicio. Para obtener más información, consulta Cómo escuchar eventos de Data Layer.