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: 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 objeto PutDataRequest y especifica una ruta de acceso de strings para identificar el elemento de forma única.
  2. Llama a setData() a fin de 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 mediante setData(), te recomendamos que uses 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 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 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. La 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() a fin de obtener un mapa de datos en el que puedas establecer valores.
  3. Configura los valores deseados 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 a fin de solicitar que el sistema cree el elemento de datos.

    Nota: Si el teléfono celular o el dispositivo 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 para la sincronización de DataItems. Por lo general, el sistema puede retrasar la publicación de DataItems en la red de Wear a los efectos de 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 urgentes. 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 llamando a setUrgent().

Si no llamas a setUrgent(), el sistema puede tardar hasta 30 minutos en sincronizar los DataItems no urgentes. No obstante, la demora suele ser de unos pocos 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 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
            }
        }
    }

    // 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 objeto de escucha del 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.