Ao chamar a API Data Layer, você pode receber o status da chamada quando ela for concluída. Também é possível ouvir 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 de exemplo 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
DataClient classe, podem retornar um objeto Task<ResultType>. Assim que o objeto Task é criado, a operação é enfileirada em segundo plano.
Se você não fizer mais nada depois disso, a operação será concluída silenciosamente.
No entanto, geralmente é necessário fazer 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 e use uma corrotina para chamar putDataItem:
private suspend fun Context.sendDataAsync(count: Int) { try { val putDataReq: PutDataRequest = PutDataMapRequest.create("/count").run { dataMap.putInt("count_key", count) asPutDataRequest() } val dataItem = Wearable.getDataClient(this).putDataItem(putDataReq).await() handleDataItem(dataItem) } catch (e: Exception) { handleDataItemError(e) } finally { handleTaskComplete() } } private fun handleDataItem(dataItem: DataItem) { } private fun handleDataItemError(exception: Exception) { } private fun handleTaskComplete() { }
Consulte a API Task para descobrir outras possibilidades, incluindo a opção de encadear a execução de tarefas diferentes.
Chamadas síncronas
Se o código estiver sendo executado em outra linha de execução do gerenciador em um serviço em segundo plano,
como no caso de WearableListenerService, use runBlocking para fazer uma
chamada de bloqueio para putDataItem.
Observação:não faça essa chamada na linha de execução principal.
private fun Context.sendDataSync(count: Int) = runBlocking { val putDataReq = PutDataMapRequest.create("/count").run { dataMap.putInt("count_key", count) asPutDataRequest() } try { val result = Wearable.getDataClient(this@sendDataSync) .putDataItem(putDataReq) .await() // Logic for success } catch (e: Exception) { // Handle failure } }
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 ouvir 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:
- Criar um serviço que estenda o
WearableListenerService. - Criar uma atividade ou classe que implemente a
DataClient.OnDataChangedListenerinterface.
Com ambas as opções, é possível substituir os métodos de callback de evento de dados para os eventos que você pretende gerenciar.
Observação:considere o uso da bateria do app ao escolher qual listener será implementado. Um WearableListenerService é registrado no arquivo de manifesto e pode iniciar o app se ele ainda não estiver em execução. Se você só precisar ouvir eventos quando o app já estiver em execução, o que geralmente acontece com aplicativos interativos, não use um WearableListenerService. Em vez disso, registre um listener em tempo real. Por exemplo, use o addListener método da
DataClient classe. Isso pode reduzir a carga no sistema e 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 tiver interesse em eventos de dados em um dos apps, não será necessário implementar o serviço nesse app.
Por exemplo, você pode ter um app portátil que configura e recebe objetos de itens de dados e um app para wearables que detecta essas alterações para atualizar a interface. Como o app para wearables nunca atualiza nenhum item de dados, o app para dispositivos portáteis não ouve eventos de dados dele.
Alguns dos eventos que podem ser detectados usando WearableListenerService são os seguintes:
onDataChanged(): sempre que um objeto de item de dados é criado, excluído ou modificado, 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 app fica disponível na rede, o evento aciona esse callback. Caso precise de um nó próximo, você pode consultar oisNearby()método dos nós fornecidos no callback.
Também é possível ouvir eventos de ChannelClient.ChannelCallback, como
onChannelOpened().
Todos os eventos acima são executados em uma linha de execução em segundo plano, e não na principal.
Para criar um WearableListenerService, siga estas etapas:
- Crie uma classe que estenda o
WearableListenerService. - Ouça os eventos de seu 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
O filtro de intent para o exemplo 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 o app tem interesse em eventos de camada de dados.
Neste exemplo, o relógio ouve o item de dados /start-activity, e o smartphone ouve a resposta da 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, é necessário definir um caractere curinga ou um host específico. Caso contrário, o caminho definido vai ser ignorado pelo sistema.
Para saber mais sobre os tipos de filtro com suporte no Wear OS, consulte a documentação de referência da API
para WearableListenerService.
Para saber mais 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, todos os atributos do caminho serão ignorados pelo sistema.
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.
Para uma abordagem mais limpa e segura, use um observador de ciclo de vida. Ao usar um
observador de ciclo de vida, você move a lógica de registro do
LifecycleResumeEvent da atividade para uma classe separada e reutilizável que
implementa DefaultLifecycleObserver.
Essa abordagem mantém a atividade simples e evita bugs comuns, como esquecer de cancelar o registro do listener.
1. Criar o listener com reconhecimento de ciclo de vida
Essa classe envolve o DataClient.OnDataChangedListener e gerencia automaticamente
a própria assinatura com base no ciclo de vida da atividade.
class WearDataLayerObserver( private val dataClient: DataClient, private val onDataReceived: (DataEventBuffer) -> Unit ) : DefaultLifecycleObserver, DataClient.OnDataChangedListener { // Implementation of the DataClient listener override fun onDataChanged(dataEvents: DataEventBuffer) { onDataReceived(dataEvents) } // Automatically register when the Activity starts override fun onResume(owner: LifecycleOwner) { dataClient.addListener(this) } // Automatically unregister when the Activity pauses override fun onPause(owner: LifecycleOwner) { dataClient.removeListener(this) } }
2. Uso na atividade
Agora, a atividade não precisa usar LifecycleResumeEvent ou
onPause para a API Wear. Registre o observador uma vez em LaunchedEvent (ou onCreate).
class DataLayerLifecycleActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val dataClient = Wearable.getDataClient(this) // Create the observer and link it to the activity's lifecycle val wearObserver = WearDataLayerObserver(dataClient) { dataEvents -> handleDataEvents(dataEvents) } lifecycle.addObserver(wearObserver) } private fun handleDataEvents(dataEvents: DataEventBuffer) { // ... filter and process events ... } }
Por que isso é melhor:
- Atividade mais limpa:você remove o código clichê dos métodos de ciclo de vida da atividade.
- Segurança:
DefaultLifecycleObserverajuda a verificar se o listener foi removido, mesmo que a atividade seja destruída inesperadamente, evitando vazamentos de memória. - Reutilização:é possível conectar esse
WearDataLayerObservera qualquer atividade ou elemento combinável sem reescrever a lógica de registro. - Desacoplamento:a lógica de quando ouvir é separada da lógica do que fazer com os dados.
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
usando collectAsStateWithLifecycle(). Ao implementar listeners dessa maneira, o app pode receber eventos de forma mais seletiva, melhorando o design e a eficiência.