Cómo sincronizar elementos de datos con la API de Data Layer

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: Un array de bytes que puedes configurar con los datos, 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: Una string única que debe comenzar con una barra diagonal, como "/path/to/data".

Nota: La API de Data Layer solo puede enviar mensajes y sincronizar datos con teléfonos Android o relojes Wear OS. Es decir, si tu dispositivo Wear OS está vinculado con un dispositivo iOS, la API de Data Layer no funcionará.

Por este motivo, no debes usar la API de Data Layer como el método principal para comunicarte con una red. En cambio, sigue el mismo patrón que una app para dispositivos móviles, con algunas diferencias menores.

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

  1. Crea un objeto 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 perjudica 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.

Cuando solicite elementos de datos, el sistema mostrará objetos que implementan adecuadamente la interfaz DataItem. Sin embargo, en lugar de trabajar con bytes sin procesar con setData(), te recomendamos que uses un mapa de datos, que expone un elemento de datos con una interfaz similar a Bundle.

Para obtener más información, consulta la app de Ejemplo de DataLayer.

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 tú 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 cadena 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. La ruta debe comenzar con una barra diagonal. Si usas datos jerárquicos en tu app, crea 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. Configura valores para el mapa de datos con 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 teléfono celular 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);
    }
  ...
}

Si deseas obtener más información para manejar Tasks, consulta la documentación de referencia.

Cómo establecer la prioridad de DataItem

La API de DataClient permite solicitudes urgentes para la sincronización de objetos DataItem. Por lo general, el sistema retrasa la entrega de los elementos de datos a la red de Wear OS para mejorar la duración de la batería de los dispositivos del usuario, pero si una demora en la sincronización de elementos de datos afecta negativamente la experiencia del usuario, puedes marcarlos como urgentes. Por ejemplo, en el caso de una app de control remoto en la que el usuario espera que se reflejen de inmediato sus acciones, puedes hacer que el sistema sincronice al instante tus elementos de datos con una llamada a setUrgent().

Si no llamas a setUrgent(), el sistema puede tardar hasta 30 minutos en sincronizar los elementos de datos no urgentes. Sin embargo, la demora suele ser de unos pocos minutos. La urgencia predeterminada es "no urgente", por lo que debes usar setUrgent() si necesitas conservar el comportamiento de sincronización inmediata de las versiones anteriores de la API de Wear OS.

Cómo detectar eventos de elementos de datos

Si un extremo de la conexión de Data Layer modifica un elemento de datos, notifica al usuario cualquier cambio 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 del 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
            }
        }
    }

    // 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) { ... }
    ...
}

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 objeto de escucha del método onPause(). Para ver una implementación con imágenes, modelos de vista y servicios, consulta la app de Ejemplo de DataLayer.

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