Ao chamar a API Data Layer, você pode receber o status da chamada quando ela for concluída. Também é possível detectar eventos de dados resultantes de mudanças feitas pelo app em qualquer local da rede do Wear OS by Google.
Para um exemplo de como trabalhar com a API Data Layer de maneira eficaz, consulte o app Android DataLayer Sample (link em inglês).
Aguardar o status das chamadas de Data Layer
As chamadas para a API Data Layer, por exemplo, usando o método putDataItem da classe
DataClient, às vezes retornam um objeto Task<ResultType>. Assim que o objeto Task é criado, a operação é colocada na fila em segundo plano.
Se você não fizer nada depois disso, a operação será concluída silenciosamente.
No entanto, é mais provável que você faça algo com o resultado após a conclusão da operação. Por isso, o objeto Task permite aguardar o status do resultado de forma assíncrona ou síncrona.
Chamadas assíncronas
Se o código estiver sendo executado na linha de execução de interface principal, não faça chamadas de bloqueio para a
API Data Layer. Execute as chamadas de forma assíncrona adicionando um método de callback ao
objeto Task, que será acionado quando a operação for concluída:
// Using Kotlin function references
task.addOnSuccessListener(::handleDataItem)
task.addOnFailureListener(::handleDataItemError)
task.addOnCompleteListener(::handleTaskComplete)
...
fun handleDataItem(dataItem: DataItem) { ... }
fun handleDataItemError(exception: Exception) { ... }
fun handleTaskComplete(task: Task<DataItem>) { ... }
Consulte a API Task para outras possibilidades, incluindo o encadeamento da execução de diferentes tarefas.
Chamadas síncronas
Se o código está sendo executado em outra linha de execução do gerenciador em um serviço em segundo plano,
como no caso de WearableListenerService, não há problema em fazer chamadas de bloqueio.
Nesse caso, chame Tasks.await() no objeto Task, que
fica bloqueado até que a solicitação seja concluída e retorne um objeto Result. Isso é mostrado
no exemplo a seguir.
Observação:não faça essa chamada na linha de execução principal.
try {
Tasks.await(dataItemTask).apply {
Log.d(TAG, "Data item set: $uri")
}
}
catch (e: ExecutionException) { ... }
catch (e: InterruptedException) { ... }
Ouvir eventos da Data Layer
Como a camada de dados sincroniza e envia dados entre o dispositivo portátil e o wearable, geralmente é necessário detectar eventos importantes, como a criação de itens de dados e o recebimento de mensagens.
Para detectar eventos de camada de dados, você tem duas opções:
- Crie um serviço que estenda
WearableListenerService. - Crie uma atividade ou classe que implemente a interface
DataClient.OnDataChangedListener.
Com as duas opções, você pode modificar os métodos de callback de evento de dados para os eventos que você está interessado em gerenciar.
Observação:considere o consumo de bateria do app ao escolher uma implementação
de listener. Um WearableListenerService é registrado no manifesto do app
e pode iniciar o app se ele ainda não estiver em execução. Se você só precisa detectar eventos quando o app já está em execução, o que geralmente é o caso para apps interativos, não use um WearableListenerService. Em vez disso,
registre um listener ativo. Por exemplo, use o método addListener da classe
DataClient. Isso pode reduzir a carga no sistema e, assim, reduzir o uso da bateria.
Usar um WearableListenerService
Geralmente, é possível criar instâncias de WearableListenerService tanto no app para dispositivos portáteis
quanto no app para wearables. No entanto, se você não quiser usar eventos de dados em
um dos apps, não é necessário implementar o serviço nele.
Por exemplo, você pode ter um app portátil que configura e recebe objetos de itens de dados e um app wearable que detecta essas alterações para atualizar a IU. O app para wearables nunca atualiza nenhum item de dados, então o app para dispositivos portáteis não detecta eventos de dados do app para wearables.
Alguns dos eventos que podem ser detectados usando WearableListenerService são:
onDataChanged(): sempre que um objeto de item de dados é criado, excluído ou alterado, o sistema aciona esse callback em todos os nós conectados.onMessageReceived(): uma mensagem enviada de um nó aciona esse callback no nó de destino.onCapabilityChanged(): quando um recurso divulgado por uma instância do seu app fica disponível na rede, o evento aciona esse callback. Se você estiver procurando um nó próximo, é possível consultar o métodoisNearby()dos nós fornecidos no callback.
Também é possível detectar eventos do ChannelClient.ChannelCallback, como
onChannelOpened().
Todos os eventos acima são executados em uma linha de execução em segundo plano, não na principal.
Para criar um WearableListenerService, siga estas etapas:
- Crie uma classe que estenda o
WearableListenerService. - Detecte eventos em que você tenha interesse, como
onDataChanged(). - Declare um filtro de intent no manifesto do Android para notificar o sistema sobre
seu
WearableListenerService. Isso permite que o sistema vincule o serviço conforme necessário.
O exemplo a seguir mostra como implementar um WearableListenerService:
class DataLayerListenerService : WearableListenerService() { override fun onDataChanged(dataEvents: DataEventBuffer) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "onDataChanged: $dataEvents") } // Loop through the events and send a message // to the node that created the data item. dataEvents .map { it.dataItem.uri } .forEach { uri -> // Get the node ID from the host value of the URI. val nodeId: String = uri.host!! // Set the data of the message to be the bytes of the URI. val payload: ByteArray = uri.toString().toByteArray() // Send the RPC. Wearable.getMessageClient(this) .sendMessage( nodeId, DATA_ITEM_RECEIVED_PATH, payload ) } } }
A próxima seção explica como usar um filtro de intent com esse listener.
Usar filtros com o WearableListenerService
Um filtro de intent para o exemplo de WearableListenerService mostrado na seção
anterior pode ter a seguinte aparência:
<service android:name=".snippets.datalayer.DataLayerListenerService" android:exported="true" tools:ignore="ExportedService" > <intent-filter> <action android:name="com.google.android.gms.wearable.DATA_CHANGED" /> <data android:scheme="wear" android:host="*" android:path="/start-activity" /> </intent-filter> </service>
O filtro de ação DATA_CHANGED informa ao sistema que seu app tem interesse em eventos da camada
de dados.
Neste exemplo, o smartwatch detecta o item de dados /start-activity, e o
smartphone detecta a resposta de mensagem /data-item-received (DATA_ITEM_RECEIVED_PATH).
As regras padrão de correspondência de filtros Android são aplicáveis. É possível especificar vários serviços
por manifesto, vários filtros de intent por serviço, várias ações por filtro
e várias estrofes de dados por filtro. Os filtros podem corresponder a um host curinga ou
específico. Para fazer correspondência com um host curinga, use host="*". Para fazer correspondência com um host específico, especifique host=<node_id>.
Também é possível fazer correspondência com um caminho literal ou prefixo de caminho. Para isso, especifique um caractere curinga ou um host específico. Caso contrário, o caminho definido vai ser ignorado pelo sistema.
Para mais informações sobre os tipos de filtro compatíveis com o Wear OS, consulte a documentação de referência da API para WearableListenerService.
Para mais informações sobre filtros de dados e regras de correspondência, consulte a documentação de referência da API para o elemento de manifesto <data>.
Tenha em mente duas regras importantes ao fazer a correspondência de filtros de intent:
- Se nenhum esquema for especificado para o filtro de intent, o sistema vai ignorar todos os outros atributos de URI.
- Se nenhum host for especificado para o filtro, o sistema vai ignorar todos os atributos de caminho.
Usar um listener em tempo real
Caso o app se importe com eventos de camada de dados somente quando o usuário estiver interagindo com ele, pode não ser necessário ter um serviço de execução longa para processar cada alteração de dados. Nesse caso, é possível ouvir eventos em uma atividade implementando uma ou mais das interfaces abaixo:
DataClient.OnDataChangedListenerMessageClient.OnMessageReceivedListenerCapabilityClient.OnCapabilityChangedListenerChannelClient.ChannelCallback
Para criar uma atividade que detecta eventos de dados, siga estas etapas:
- Implemente as interfaces necessárias.
- No método
onCreate()ouonResume(), chameWearable.getDataClient(this).addListener(),MessageClient.addListener(),CapabilityClient.addListener()ouChannelClient.registerChannelCallback()para notificar o Google Play Services que a atividade precisa detectar eventos da camada de dados. - Em
onStop()ouonPause(), cancele o registro de listeners comDataClient.removeListener(),MessageClient.removeListener(),CapabilityClient.removeListener()ouChannelClient.unregisterChannelCallback(). - Se uma atividade só precisar receber eventos com um prefixo de caminho específico, adicione um listener com um filtro de prefixos para receber apenas dados relevantes ao estado atual do aplicativo.
- Implemente
onDataChanged(),onMessageReceived(),onCapabilityChanged()ou métodos deChannelClient.ChannelCallback, dependendo das interfaces que você implementou. Esses métodos são chamados na linha de execução principal, ou você pode especificar umLooperpersonalizado usandoWearableOptions.
Confira um exemplo que implementa DataClient.OnDataChangedListener:
class MainActivity : Activity(), DataClient.OnDataChangedListener { public 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 -> if (event.type == DataEvent.TYPE_DELETED) { Log.d(TAG, "DataItem deleted: " + event.dataItem.uri) } else if (event.type == DataEvent.TYPE_CHANGED) { Log.d(TAG, "DataItem changed: " + event.dataItem.uri) } } } }
Atenção:antes de usar a API Wearable Data Layer, verifique se ela está disponível
em um dispositivo. Caso contrário, uma exceção vai ocorrer. Use a classe
GoogleApiAvailability, conforme implementado no Horologist.
Usar filtros com listeners em tempo real
Como mencionado anteriormente, assim como é possível especificar filtros de intent para
objetos WearableListenerService do manifesto, também é possível usar filtros de intent
ao registrar um listener em tempo real usando a API Wearable. As mesmas regras
se aplicam aos listeners em tempo real da API e aos listeners do manifesto.
Um padrão comum é registrar um listener com um caminho específico ou prefixo de caminho
no método onResume() de uma atividade e remover o listener no
método onPause() da atividade. Implementar listeners dessa maneira
permite que o app receba eventos de forma mais seletiva, melhorando o design e
a eficiência.