Sincronizar itens de dados com a API Data Layer

Um DataItem define a interface que o sistema usa para sincronizar dados entre os dispositivos portáteis e os wearables. Um DataItem geralmente é formado pelos seguintes componentes:

  • Payload: uma matriz de bytes que pode ser definida com dados, o que possibilita a serialização e desserialização de objetos. O tamanho do payload é limitado a 100 KB.
  • Caminho: uma string exclusiva que precisa começar com uma barra, como "/path/to/data".

Observação: a API Data Layer só pode enviar mensagens e sincronizar dados com smartphones Android ou relógios Wear OS. Se o dispositivo Wear OS estiver pareado com um dispositivo iOS, a API Data Layer não vai funcionar.

Por esse motivo, não use a API Data Layer como principal forma de comunicação com uma rede. Em vez disso, siga o mesmo padrão de um app para dispositivos móveis, com algumas pequenas diferenças.

Normalmente, não é possível implementar o DataItem diretamente. Em vez disso, faça o seguinte:

  1. Crie um objeto PutDataRequest, especificando um caminho de string para identificar o item de maneira exclusiva.
  2. Chame setData() para definir o payload.
  3. Se um atraso na sincronização impactar negativamente a experiência do usuário, chame setUrgent().
  4. Use o método putDataItem da classe DataClient para solicitar que o sistema crie o item de dados.

Ao solicitar itens de dados, o sistema retorna objetos que implementam corretamente a interface de DataItem. No entanto, em vez de trabalhar com bytes brutos usando setData(), recomendamos que você use um mapa de dados, que expõe um item de dados com uma interface do tipo Bundle.

Para saber mais, consulte o app Exemplo de DataLayer.

Sincronizar dados com um mapa de dados

Sempre que possível, use a classe DataMap. Essa abordagem permite que você trabalhe com itens de dados na forma de um Bundle Android, para que o sistema realize a serialização e desserialização de objetos e você possa manipular dados com pares de chave-valor.

Para usar um mapa de dados:

  1. Crie um objeto PutDataMapRequest configurando o caminho do item de dados.

    Observação: a string do caminho é um identificador exclusivo para o item de dados que permite que você o acesse de ambos os lados da conexão. O caminho precisa começar com uma barra. Se você estiver usando dados hierárquicos no app, crie um esquema de caminho que corresponda à estrutura dos dados.

  2. Chame PutDataMapRequest.getDataMap() para receber um mapa de dados em que seja possível definir valores.
  3. Defina valores para o mapa de dados usando os métodos put...(), como putString().
  4. Se um atraso na sincronização impactar negativamente a experiência do usuário, chame setUrgent().
  5. Chame PutDataMapRequest.asPutDataRequest() para conseguir um objeto PutDataRequest.
  6. Use o método putDataItem da classe DataClient para solicitar que o sistema crie o item de dados.

    Observação: se os dispositivos portáteis e wearables forem desconectados, os dados serão armazenados em buffer e sincronizados quando a conexão for restabelecida.

O método increaseCounter() no exemplo a seguir mostra como criar um mapa de dados e inserir dados nele:

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 mais informações sobre como lidar com Tasks, consulte a documentação de referência.

Definir prioridade de DataItem

A API DataClient permite solicitações urgentes de sincronização de objetos DataItem. Normalmente, o sistema atrasa a entrega de itens de dados à rede do Wear OS para melhorar a duração da bateria dos dispositivos do usuário. No entanto, se um atraso na sincronização de itens de dados afetar negativamente a experiência do usuário, você pode marcá-los como urgentes. Por exemplo, em um app de controle remoto em que o usuário espera resposta às ações, é possível fazer com que o sistema sincronize seus itens de dados imediatamente chamando setUrgent().

Se o método setUrgent() não for chamado, o sistema pode levar até 30 minutos para sincronizar itens de dados não urgentes, embora normalmente o atraso seja de apenas alguns minutos. O nível de urgência padrão é não urgente. Portanto, use setUrgent() se precisar manter o comportamento de sincronização imediata das versões anteriores da API Wear OS.

Detectar eventos de item de dados

Se um lado da conexão de camada de dados mudar um item de dados, notifique o usuário sobre qualquer mudança no outro lado da conexão. Para fazer isso, implemente um listener para eventos de itens de dados.

O snippet de código no exemplo a seguir notifica o app quando o valor do contador definido no exemplo acima mudar:

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

Essa atividade implementa a interface DataClient.OnDataChangedListener. A atividade se adiciona como listener para eventos de itens de dados dentro do método onResume() e remove o listener no método onPause(). Para ver uma implementação usando imagens, visualizar modelos e serviços, consulte o Exemplo de DataLayer app.

Também é possível implementar o listener como serviço. Para saber mais, consulte Detectar eventos de camadas de dados.