Sincronizar itens de dados no Wear

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 configurada com quaisquer dados desejados, permitindo que você faça a própria serialização e desserialização de objetos. O tamanho do payload é limitado a 100 KB.
  • Caminho: uma string única que precisa começar com uma barra (por exemplo, "/path/to/data").

Observação: um app para Wear pode se comunicar com um app para smartphone usando a API Data Layer, mas não é recomendado se conectar a uma rede usando essa API.

Normalmente, não é possível implementar 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 fácil de usar.

Confira os seguintes recursos relacionados:

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 seu app, será necessário criar 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 os valores desejados 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 DataItems. Normalmente, o sistema pode atrasar a entrega de DataItems à rede do Wear para melhorar a duração da bateria dos dispositivos do usuário, mas se um atraso na sincronização de DataItems afetar negativamente a experiência do usuário, é possível marcar o item como urgente. 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 DataItems imediatamente chamando setUrgent().

Se setUrgent() não for chamado, o sistema poderá levar até 30 minutos para sincronizar DataItems não urgentes, mas o atraso costuma ser de apenas alguns minutos, se houver. O nível de urgência padrão no momento é não urgente, então é necessário usar setUrgent() caso você queira manter o comportamento de sincronização imediata que havia em versões anteriores da API Wear.

Detectar eventos de item de dados

Se um lado da conexão de camada de dados alterar um item de dados, você provavelmente vai querer ser notificado de quaisquer alterações no outro lado na 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
            }
        }
    }

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

    ...
}

Essa atividade implementa a interface DataClient.OnDataChangedListener. Essa atividade se adiciona como listener para eventos de itens de dados dentro do método onResume() e remove o listener no método onPause().

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