Wenn Sie einen Aufruf an die Data Layer API senden, können Sie den Status des Aufrufs nach Abschluss abrufen. Sie können auch auf Datenereignisse reagieren, die durch Datenänderungen ausgelöst werden, die Ihre App an beliebiger Stelle im Wear OS by Google-Netzwerk vornimmt.
Ein Beispiel für die effektive Verwendung der Data Layer API finden Sie in der Android DataLayer Sample App.
Auf den Status von Datenschichtaufrufen warten
Bei Aufrufen der Data Layer API, z. B. mit der Methode putDataItem der Klasse DataClient, wird manchmal ein Task<ResultType>-Objekt zurückgegeben. Sobald das Task-Objekt erstellt wurde, wird der Vorgang im Hintergrund in die Warteschlange gestellt.
Wenn Sie danach nichts weiter unternehmen, wird der Vorgang irgendwann im Hintergrund abgeschlossen.
In der Regel möchten Sie jedoch nach Abschluss des Vorgangs etwas mit dem Ergebnis tun. Mit dem Task-Objekt können Sie asynchron oder synchron auf den Ergebnisstatus warten.
Asynchrone Aufrufe
Wenn Ihr Code im Haupt-UI-Thread ausgeführt wird, sollten Sie keine blockierenden Aufrufe der Data Layer API vornehmen und eine Coroutine verwenden, um putDataItem aufzurufen:
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() { }
Weitere Möglichkeiten, z. B. das Verketten der Ausführung verschiedener Aufgaben, finden Sie in der Task API.
Synchrone Aufrufe
Wenn Ihr Code in einem separaten Handler-Thread in einem Hintergrunddienst ausgeführt wird, z. B. in einem WearableListenerService, verwenden Sie runBlocking, um einen blockierenden Aufruf an putDataItem zu senden.
Hinweis:Rufen Sie diese Funktion nicht im Hauptthread auf.
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 } }
Auf Datenschichtereignisse warten
Da die Datenschicht Daten zwischen dem Smartphone und dem Wearable synchronisiert und sendet, müssen Sie in der Regel auf wichtige Ereignisse wie das Erstellen von Datenobjekten und den Empfang von Nachrichten warten.
Sie haben zwei Möglichkeiten, Datenschichtereignisse zu erfassen:
- Erstelle einen Dienst, der
WearableListenerServiceerweitert. - Erstelle eine Aktivität oder Klasse, die die Schnittstelle
DataClient.OnDataChangedListenerimplementiert.
Bei beiden Optionen überschreiben Sie die Data Event-Callback-Methoden für die Ereignisse, die Sie verarbeiten möchten.
Hinweis:Berücksichtigen Sie bei der Auswahl einer Listener-Implementierung die Akkunutzung Ihrer App. Ein WearableListenerService ist im Manifest der App registriert und kann die App starten, wenn sie noch nicht ausgeführt wird. Wenn Sie nur auf Ereignisse warten müssen, wenn Ihre App bereits ausgeführt wird, was bei interaktiven Anwendungen häufig der Fall ist, verwenden Sie kein WearableListenerService. Registrieren Sie stattdessen einen Live-Listener. Verwenden Sie beispielsweise die Methode addListener der Klasse DataClient. Dadurch kann die Belastung des Systems und der Akkuverbrauch reduziert werden.
WearableListenerService verwenden
Normalerweise erstellen Sie Instanzen von WearableListenerService sowohl in Ihren Wearable- als auch in Ihren Handheld-Apps. Wenn Sie jedoch kein Interesse an Datenereignissen in einer der Apps haben, müssen Sie den Dienst in dieser App nicht implementieren.
Sie können beispielsweise eine Handheld-App haben, die Datenobjekte festlegt und abruft, und eine Wearable-App, die auf diese Aktualisierungen wartet, um ihre Benutzeroberfläche zu aktualisieren. Die Wearable-App aktualisiert keine der Daten-Items. Die Smartphone-App wartet daher nicht auf Datenereignisse von der Wearable-App.
Einige der Ereignisse, auf die Sie mit WearableListenerService warten können, sind die folgenden:
onDataChanged(): Immer wenn ein Datenobjekt erstellt, gelöscht oder geändert wird, löst das System diesen Callback für alle verbundenen Knoten aus.onMessageReceived(): Eine von einem Knoten gesendete Nachricht löst diesen Callback auf dem Zielknoten aus.onCapabilityChanged(): Wenn eine Funktion, die eine Instanz Ihrer App bewirbt, im Netzwerk verfügbar wird, löst dieses Ereignis diesen Callback aus. Wenn Sie nach einem Knoten in der Nähe suchen, können Sie die MethodeisNearby()der im Callback bereitgestellten Knoten abfragen.
Sie können auch auf Ereignisse von ChannelClient.ChannelCallback warten, z. B. onChannelOpened().
Alle vorherigen Ereignisse werden in einem Hintergrundthread und nicht im Hauptthread ausgeführt.
So erstellen Sie eine WearableListenerService:
- Erstellen Sie eine Klasse, die
WearableListenerServiceerweitert. - Hören Sie auf die Ereignisse, die Sie interessieren, z. B.
onDataChanged(). - Deklarieren Sie in Ihrem Android-Manifest einen Intent-Filter, um das System über Ihre
WearableListenerServicezu informieren. Durch diese Deklaration kann das System Ihren Dienst nach Bedarf binden.
Das folgende Beispiel zeigt, wie Sie eine WearableListenerService implementieren:
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 ) } } }
Im folgenden Abschnitt wird erläutert, wie Sie einen Intent-Filter mit diesem Listener verwenden.
Filter mit WearableListenerService verwenden
Ein Intent-Filter für das WearableListenerService-Beispiel aus dem vorherigen Abschnitt könnte so aussehen:
<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>
Der Aktionsfilter DATA_CHANGED teilt dem System mit, dass Ihre App an Data-Layer-Ereignissen interessiert ist.
In diesem Beispiel wartet die Smartwatch auf das Datenelement /start-activity und das Smartphone auf die Antwort der Nachricht /data-item-received (DATA_ITEM_RECEIVED_PATH).
Es gelten die Standardregeln für den Android-Filterabgleich. Sie können mehrere Dienste pro Manifest, mehrere Intent-Filter pro Dienst, mehrere Aktionen pro Filter und mehrere Datenabschnitte pro Filter angeben. Filter können auf einen Platzhalterhost oder auf einen bestimmten Host abgestimmt werden. Verwenden Sie host="*", um einen Platzhalterhost abzugleichen. Wenn Sie einen bestimmten Host abgleichen möchten, geben Sie host=<node_id> an.
Sie können auch einen Literalpfad oder ein Pfadpräfix abgleichen. Dazu müssen Sie einen Platzhalter oder einen bestimmten Host angeben. Andernfalls wird der angegebene Pfad vom System ignoriert.
Weitere Informationen zu den von Wear OS unterstützten Filtertypen finden Sie in der API-Referenzdokumentation zu WearableListenerService.
Weitere Informationen zu Datenfiltern und Abgleichsregeln finden Sie in der API-Referenzdokumentation zum Manifestelement <data>.
Beim Abgleichen von Intent-Filtern sind zwei wichtige Regeln zu beachten:
- Wenn kein Schema für den Intent-Filter angegeben ist, ignoriert das System alle anderen URI-Attribute.
- Wenn für den Filter kein Host angegeben ist, ignoriert das System alle Pfadattribute.
Live-Zuhörer verwenden
Wenn Ihre App nur auf Datenschichtereignisse reagieren muss, wenn der Nutzer mit der App interagiert, ist möglicherweise kein Dienst erforderlich, der lange ausgeführt wird, um jede Datenänderung zu verarbeiten. In diesem Fall können Sie Ereignisse in einer Aktivität erfassen.
Um einen saubereren und sichereren Ansatz zu empfehlen, verwenden Sie einen Lifecycle Observer. Wenn Sie einen Lifecycle-Observer verwenden, verschieben Sie die Registrierungslogik aus der onResume() der Aktivität in eine separate, wiederverwendbare Klasse, die DefaultLifecycleObserver implementiert.
So bleibt Ihre Aktivität schlank und häufige Fehler wie das Vergessen, den Listener abzumelden, werden vermieden.
1. Lifecycle-aware Listener erstellen
Diese Klasse umschließt DataClient.OnDataChangedListener und verwaltet automatisch ihr eigenes Abo basierend auf dem Lebenszyklus der Aktivität.
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. Nutzung in Ihren Aktivitäten
Ihre Aktivität muss onResume() oder onPause() für die Wear API nicht mehr überschreiben. Sie fügen den Beobachter einmal in onCreate() hinzu.
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 ... } }
Warum das besser ist:
- Cleaner Activity:Sie entfernen Boilerplate-Code aus den Methoden des Activity-Lebenszyklus.
- Sicherheit:Mit
DefaultLifecycleObserverwird sichergestellt, dass der Listener entfernt wird, auch wenn die Aktivität unerwartet beendet wird. So werden Speicherlecks verhindert. - Wiederverwendbarkeit:Sie können dieses
WearDataLayerObserverin jede Activity oder jedes Fragment einfügen, ohne die Registrierungslogik neu schreiben zu müssen. - Entkopplung:Die Logik dafür, wann auf das Mikrofon zugegriffen werden soll, ist von der Logik dafür getrennt, was mit den Daten geschehen soll.
Filter mit Live-Zuhörern verwenden
Wie bereits erwähnt, können Sie Intent-Filter für manifestbasierte WearableListenerService-Objekte angeben. Sie können Intent-Filter auch verwenden, wenn Sie einen Live-Listener über die Wearable API registrieren. Für API-basierte und manifestbasierte Live-Listener gelten dieselben Regeln.
Ein häufiges Muster besteht darin, einen Listener mit einem bestimmten Pfad oder Pfadpräfix mithilfe von LifecycleObserver zu registrieren. Durch die Implementierung von Listenern auf diese Weise kann Ihre App Ereignisse selektiver empfangen, was das Design und die Effizienz verbessert.