Wenn Sie die Data Layer API aufrufen, 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
Aufrufe der Data Layer API, z. B. ein Aufruf mit der Methode putDataItem
der Klasse
DataClient
, geben manchmal ein
Task<ResultType>
-Objekt zurück. Sobald das Task
-Objekt erstellt wurde, wird der Vorgang im Hintergrund in die Warteschlange gestellt. Wenn Sie danach nichts weiter unternehmen, wird der Vorgang schließlich 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 Anrufe
Wenn Ihr Code im Haupt-UI-Thread ausgeführt wird, sollten Sie keine blockierenden Aufrufe an die Data Layer API vornehmen. Führen Sie die Aufrufe asynchron aus, indem Sie dem Task
-Objekt eine Callback-Methode hinzufügen, die ausgelöst wird, wenn der Vorgang abgeschlossen ist:
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));
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 Hintergrunddienst in einem separaten Handler-Thread ausgeführt wird, z. B. in einem
WearableListenerService
, können die Aufrufe blockiert werden. In diesem Fall können Sie Tasks.await()
für das Task
-Objekt aufrufen. Dadurch wird der Vorgang blockiert, bis die Anfrage abgeschlossen ist, und ein Result
-Objekt zurückgegeben. Dies wird im folgenden Beispiel veranschaulicht.
Hinweis:Rufen Sie diese Funktion nicht im Hauptthread auf.
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) { ... }
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 Datenelementen und den Empfang von Nachrichten warten.
Sie haben zwei Möglichkeiten, Datenschichtereignisse zu erfassen:
- Erstelle einen Dienst, der
WearableListenerService
erweitert. - Erstellen Sie eine Aktivität oder Klasse, die die
DataClient.OnDataChangedListener
-Schnittstelle implementiert.
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 den Akkuverbrauch Ihrer App. Ein WearableListenerService
ist im Manifest der App registriert und kann die App starten, wenn sie nicht bereits 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 keine 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 verringert werden.
WearableListenerService verwenden
Normalerweise erstellen Sie Instanzen von
WearableListenerService
sowohl in Ihren Wearable- als auch in Ihren Smartphone-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 Datenelemente. Die Smartphone-App wartet daher nicht auf Datenereignisse von der Wearable-App.
Einige der Ereignisse, auf die Sie mit WearableListenerService
warten können, sind:
-
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
WearableListenerService
erweitert. - Hören Sie auf die Ereignisse, die Sie interessieren, z. B.
onDataChanged()
. - Deklarieren Sie einen Intent-Filter in Ihrem Android-Manifest, um das System über Ihre
WearableListenerService
zu informieren. Durch diese Deklaration kann das System Ihren Dienst nach Bedarf binden.
Das folgende Beispiel zeigt, wie eine einfache WearableListenerService
implementiert wird:
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); } } }
Im folgenden Abschnitt wird beschrieben, wie Sie einen Intent-Filter mit diesem Listener verwenden.
Filter mit WearableListenerService verwenden
Ein Intent-Filter für das im vorherigen Abschnitt gezeigte Beispiel WearableListenerService
könnte so aussehen:
<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 diesem Filter ersetzt die Aktion DATA_CHANGED
die zuvor empfohlene Aktion BIND_LISTENER
, sodass nur bestimmte Ereignisse Ihre App aktivieren oder starten. Diese Änderung verbessert die Systemeffizienz und reduziert den Akkuverbrauch und andere mit Ihrer App verbundene Overheads. In diesem Beispiel wartet die Smartwatch auf das Datenelement /start-activity
und das Smartphone auf die Nachrichtenantwort /data-item-received
.
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 für
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 kein Host für den Filter 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 auf Ereignisse in einer Aktivität reagieren, indem Sie eine oder mehrere der folgenden Schnittstellen implementieren:
DataClient.OnDataChangedListener
MessageClient.OnMessageReceivedListener
CapabilityClient.OnCapabilityChangedListener
ChannelClient.ChannelCallback
So erstellen Sie eine Aktivität, die auf Datenereignisse wartet:
- Implementieren Sie die gewünschten Schnittstellen.
- Rufen Sie in der Methode
onCreate()
oderonResume()
Wearable.getDataClient(this).addListener()
,MessageClient.addListener()
,CapabilityClient.addListener()
oderChannelClient.registerChannelCallback()
auf, um die Google Play-Dienste darüber zu informieren, dass Ihre Aktivität an Data Layer-Ereignissen interessiert ist. - Heben Sie in
onStop()
oderonPause()
die Registrierung aller Listener mitDataClient.removeListener()
,MessageClient.removeListener()
,CapabilityClient.removeListener()
oderChannelClient.unregisterChannelCallback()
auf. - Wenn eine Aktivität nur an Ereignissen mit einem bestimmten Pfadpräfix interessiert ist, können Sie einen Listener mit einem entsprechenden Präfixfilter hinzufügen, um nur Daten zu empfangen, die für den aktuellen Anwendungsstatus relevant sind.
- Implementieren Sie
onDataChanged()
,onMessageReceived()
,onCapabilityChanged()
oder Methoden ausChannelClient.ChannelCallback
, je nachdem, welche Schnittstellen Sie implementiert haben. Diese Methoden werden im Hauptthread aufgerufen. Sie können aber auch einen benutzerdefiniertenLooper
mitWearableOptions
angeben.
Hier ein Beispiel für die Implementierung von 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()); } } } }
Achtung:Bevor Sie die Wearable Data Layer API verwenden, prüfen Sie, ob sie auf einem Gerät verfügbar ist. Andernfalls tritt eine Ausnahme auf. Verwenden Sie die Klasse GoogleApiAvailability
, wie sie in Horologist implementiert ist.
Filter mit Live-Listenern verwenden
Wie bereits erwähnt, können Sie Intent-Filter nicht nur für manifestbasierte WearableListenerService
-Objekte angeben, sondern 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 in der onResume()
-Methode einer Aktivität zu registrieren und den Listener dann in der onPause()
-Methode der Aktivität zu entfernen.
Wenn Sie Listener auf diese Weise implementieren, kann Ihre App Ereignisse selektiver empfangen, was das Design und die Effizienz verbessert.