Quando effettui una chiamata all'API del livello dati, puoi ricevere lo stato della chiamata al completamento. Puoi anche rimanere in ascolto degli eventi di dati derivanti dalle modifiche ai dati apportate dalla tua app ovunque sulla rete Wear OS by Google.
Per un esempio di utilizzo efficace dell'API del livello dati, consulta l' app Android Datalayer Sample.
Attendi lo stato delle chiamate del livello dati
Le chiamate all'API del livello dati, ad esempio una chiamata che utilizza il metodo putDataItem
della classe
DataClient
, a volte restituiscono un oggetto
Task<ResultType>
. Non appena viene creato l'oggetto Task
, l'operazione viene messa in coda in background. Se dopo questa operazione non fai altro, l'operazione viene completata in modo invisibile all'utente.
Tuttavia, di solito vuoi eseguire un'azione con il risultato dopo il completamento dell'operazione, quindi l'oggetto Task
ti consente di attendere lo stato del risultato, in modo asincrono o sincrono.
Chiamate asincrone
Se il codice è in esecuzione nel thread dell'interfaccia utente principale, non effettuare chiamate di blocco all'API del livello dati. Esegui le chiamate in modo asincrono aggiungendo un metodo di callback all'oggetto Task
, che si attiva quando l'operazione viene completata:
Kotlin
// 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>) { ... }
Java
// Using Java 8 Lambdas. task.addOnSuccessListener(dataItem -> handleDataItem(dataItem)); task.addOnFailureListener(exception -> handleDataItemError(exception)); task.addOnCompleteListener(task -> handleTaskComplete(task));
Consulta l' API Tasks per altre possibilità, tra cui il concatenamento dell'esecuzione di diverse attività.
Chiamate sincrone
Se il tuo codice è in esecuzione su un thread di gestore separato in un servizio in background, ad esempio in un
WearableListenerService
, le chiamate possono essere bloccate. In questo caso, puoi chiamare Tasks.await()
sull'oggetto Task
, che blocca fino al completamento della richiesta e restituisce un oggetto Result
. Questa situazione è illustrata nell'esempio seguente.
Nota:assicurati di non chiamare questa opzione mentre ti trovi nel thread principale.
Kotlin
try { Tasks.await(dataItemTask).apply { Log.d(TAG, "Data item set: $uri") } } catch (e: ExecutionException) { ... } catch (e: InterruptedException) { ... }
Java
try { DataItem item = Tasks.await(dataItemTask); Log.d(TAG, "Data item set: " + item.getUri()); } catch (ExecutionException | InterruptedException e) { ... }
Ascolta gli eventi del livello dati
Poiché il livello dati sincronizza e invia dati tra i dispositivi portatili e indossabili, in genere devi rimanere in ascolto di eventi importanti come la creazione degli elementi di dati e la ricezione dei messaggi.
Per ascoltare gli eventi del livello dati, hai due opzioni:
- Crea un servizio che estende
WearableListenerService
. - Crea un'attività o una classe che implementi l'interfaccia
DataClient.OnDataChangedListener
.
Con entrambe le opzioni, esegui l'override dei metodi di callback degli eventi dei dati per gli eventi che ti interessa gestire.
Nota: quando scegli l'implementazione di un listener, considera l'utilizzo della batteria da parte dell'app. Un WearableListenerService
viene registrato nel file manifest dell'app e può avviarla se non è già
in esecuzione. Se devi ascoltare gli eventi solo quando la tua app è già in esecuzione, come spesso avviene nel caso delle applicazioni interattive, non utilizzare WearableListenerService
. Registra invece un listener dal vivo.
Ad esempio, utilizza il metodo addListener
della classe DataClient
. Ciò può ridurre il carico sul sistema e l'utilizzo della batteria.
Usa WearableListenerService
In genere, vengono create istanze di
WearableListenerService
sia nelle app per dispositivi indossabili sia nelle app per dispositivi portatili. Tuttavia, se non ti interessano gli eventi di dati in una delle app, non è necessario implementare il servizio in quell'app.
Ad esempio, puoi avere un'app portatile che imposta e recupera oggetti di elementi di dati e un'app indossabile che ascolta questi aggiornamenti per aggiornare la sua UI. L'app indossabile non aggiorna mai alcun elemento di dati, quindi l'app portatile non rileva gli eventi di dati provenienti dall'app indossabile.
Ecco alcuni degli eventi che puoi ascoltare utilizzando WearableListenerService
:
-
onDataChanged()
: ogni volta che un oggetto elemento di dati viene creato, eliminato o modificato, il sistema attiva questo callback su tutti i nodi connessi. -
onMessageReceived()
: un messaggio inviato da un nodo attiva questo callback sul nodo di destinazione. -
onCapabilityChanged()
: quando una funzionalità pubblicizzata da un'istanza della tua app diventa disponibile sulla rete, l'evento attiva questo callback. Se stai cercando un nodo nelle vicinanze, puoi eseguire una query sul metodoisNearby()
dei nodi forniti nel callback.
Puoi anche rimanere in ascolto degli eventi di
ChannelClient.ChannelCallback
, ad esempio onChannelOpened()
.
Tutti gli eventi precedenti vengono eseguiti in un thread in background, non nel thread principale.
Per creare un WearableListenerService
, segui questi passaggi:
- Crea un corso che estenda
WearableListenerService
. - Ascolta gli eventi che ti interessano, ad esempio
onDataChanged()
. - Dichiara un filtro per intent nel file manifest Android per inviare una notifica al sistema in merito a
WearableListenerService
. Questa dichiarazione consente al sistema di associare il tuo servizio in base alle esigenze.
L'esempio seguente mostra come implementare un WearableListenerService
semplice:
Kotlin
private const val TAG = "DataLayerSample" private const val START_ACTIVITY_PATH = "/start-activity" private const val DATA_ITEM_RECEIVED_PATH = "/data-item-received" 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) } } }
Java
public class DataLayerListenerService extends WearableListenerService { private static final String TAG = "DataLayerSample"; private static final String START_ACTIVITY_PATH = "/start-activity"; private static final String DATA_ITEM_RECEIVED_PATH = "/data-item-received"; @Override public void onDataChanged(DataEventBuffer dataEvents) { 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. for (DataEvent event : dataEvents) { Uri uri = event.getDataItem().getUri(); // Get the node ID from the host value of the URI. String nodeId = uri.getHost(); // Set the data of the message to be the bytes of the URI. byte[] payload = uri.toString().getBytes(); // Send the RPC. Wearable.getMessageClient(this).sendMessage( nodeId, DATA_ITEM_RECEIVED_PATH, payload); } } }
La seguente sezione spiega come utilizzare un filtro per intent con questo listener.
Utilizzare i filtri con WearableListenerService
Un filtro per intent per l'esempio WearableListenerService
mostrato nella sezione precedente potrebbe avere il seguente aspetto:
<service android:name=".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>
In questo filtro, l'azione DATA_CHANGED
sostituisce l'azione BIND_LISTENER
consigliata in precedenza in modo che solo eventi specifici attivino o avviino l'app. Questa modifica migliora l'efficienza del sistema e riduce il consumo di batteria e altri costi aggiuntivi associati alla tua app. In questo esempio, l'orologio ascolta l'elemento di dati /start-activity
e il telefono ascolta la risposta al messaggio /data-item-received
.
Si applicano le regole di corrispondenza standard del filtro Android. Puoi specificare più servizi per manifest, più filtri di intent per servizio, più azioni per filtro e più stanze di dati per filtro. I filtri possono corrispondere su un host con caratteri jolly
o su uno specifico. Per trovare una corrispondenza su un host con caratteri jolly, utilizza host="*"
. Per trovare corrispondenze su un host specifico, specifica host=<node_id>
.
Puoi anche creare una corrispondenza con un percorso letterale o un prefisso di percorso. Per farlo, devi specificare un carattere jolly o un host specifico. In caso contrario, il sistema ignora il percorso specificato.
Per ulteriori informazioni sui tipi di filtri supportati da Wear OS, consulta la documentazione di riferimento API per
WearableListenerService
.
Per ulteriori informazioni sui filtri dei dati e sulle regole di corrispondenza, consulta la documentazione di riferimento API per l'elemento manifest <data>
.
Quando fai corrispondere i filtri per intent, tieni a mente due regole importanti:
- Se non viene specificato nessuno schema per il filtro per intent, il sistema ignora tutti gli altri attributi URI.
- Se non è specificato alcun host per il filtro, il sistema ignora tutti gli attributi del percorso.
Usare un listener dal vivo
Se alla tua app interessano gli eventi a livello dati solo quando l'utente interagisce con l'app, potrebbe non aver bisogno di un servizio a lunga esecuzione per gestire ogni modifica ai dati. In tal caso, puoi rimanere in ascolto degli eventi in un'attività implementando una o più delle seguenti interfacce:
DataClient.OnDataChangedListener
MessageClient.OnMessageReceivedListener
CapabilityClient.OnCapabilityChangedListener
ChannelClient.ChannelCallback
Per creare un'attività che ascolti gli eventi di dati:
- Implementa le interfacce desiderate.
- Nel metodo
onCreate()
oonResume()
, chiamaWearable.getDataClient(this).addListener()
,MessageClient.addListener()
,CapabilityClient.addListener()
oChannelClient.registerChannelCallback()
per comunicare a Google Play Services che la tua attività è interessata ad ascoltare eventi del livello dati. - In
onStop()
oonPause()
, annulla la registrazione di tutti gli ascoltatori conDataClient.removeListener()
,MessageClient.removeListener()
,CapabilityClient.removeListener()
oChannelClient.unregisterChannelCallback()
. - Se un'attività è interessata solo agli eventi con un prefisso percorso specifico, puoi aggiungere un listener con un filtro prefisso adatto per ricevere solo i dati pertinenti per lo stato attuale dell'applicazione.
- Implementa
onDataChanged()
,onMessageReceived()
,onCapabilityChanged()
o i metodi diChannelClient.ChannelCallback
, a seconda delle interfacce che hai implementato. Questi metodi vengono chiamati nel thread principale. In alternativa, puoi specificare unLooper
personalizzato utilizzandoWearableOptions
.
Ecco un esempio che implementa DataClient.OnDataChangedListener
:
Kotlin
class MainActivity : Activity(), DataClient.OnDataChangedListener { public override fun onResume() { Wearable.getDataClient(this).addListener(this) } override fun 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) } } } }
Java
public class MainActivity extends Activity implements DataClient.OnDataChangedListener { @Override public void onResume() { Wearable.getDataClient(this).addListener(this); } @Override protected void onPause() { Wearable.getDataClient(this).removeListener(this); } @Override public void onDataChanged(DataEventBuffer dataEvents) { for (DataEvent event : dataEvents) { if (event.getType() == DataEvent.TYPE_DELETED) { Log.d(TAG, "DataItem deleted: " + event.getDataItem().getUri()); } else if (event.getType() == DataEvent.TYPE_CHANGED) { Log.d(TAG, "DataItem changed: " + event.getDataItem().getUri()); } } } }
Utilizzare i filtri con i listener dal vivo
Come accennato in precedenza, così come puoi specificare i filtri per intent per gli oggetti WearableListenerService
basati su manifest, puoi utilizzare i filtri per intent quando registri un listener in tempo reale tramite l'API Wearable. Le stesse regole si applicano sia ai listener live basati su API sia ai listener basati su manifest.
Un pattern comune è la registrazione di un listener con un percorso o un prefisso di percorso specifico nel metodo onResume()
di un'attività per poi rimuovere il listener nel metodo onPause()
dell'attività.
L'implementazione dei listener in questo modo consente alla tua app di ricevere eventi in modo più selettivo, migliorandone il design e l'efficienza.