Gdy wywołujesz interfejs Data Layer API, po zakończeniu wywołania możesz otrzymać jego stan. Możesz też nasłuchiwać zdarzeń danych wynikających ze zmian danych wprowadzonych przez aplikację w dowolnym miejscu sieci Wear OS by Google.
Przykład skutecznej pracy z interfejsem Data Layer API znajdziesz w aplikacji przykładowej Android DataLayer.
Czekanie na stan wywołań warstwy danych
Wywołania interfejsu Data Layer API, takie jak wywołanie za pomocą metody putDataItem klasy
DataClient, czasami zwracają obiekt Task<ResultType>. Gdy tylko obiekt Task zostanie utworzony, operacja jest umieszczana w kolejce w tle.
Jeśli po tym nie zrobisz nic więcej, operacja w końcu zakończy się bez powiadomienia.
Zwykle jednak po zakończeniu operacji chcesz coś zrobić z wynikiem, dlatego obiekt Task umożliwia asynchroniczne lub synchroniczne czekanie na stan wyniku.
Wywołania asynchroniczne
Jeśli Twój kod działa w głównym wątku UI, nie wykonuj blokujących wywołań interfejsu Data Layer API i użyj współprogramu do wywołania 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() { }
Więcej informacji o innych możliwościach, w tym o łączeniu wykonania różnych zadań, znajdziesz w dokumentacji interfejsu Task API.
Wywołania synchroniczne
Jeśli Twój kod działa w osobnym wątku obsługi w usłudze działającej w tle,
np. w WearableListenerService, użyj runBlocking, aby wykonać
blokujące wywołanie putDataItem.
Uwaga: nie wywołuj tej metody w głównym wątku.
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 } }
Nasłuchiwanie zdarzeń warstwy danych
Ponieważ warstwa danych synchronizuje i wysyła dane między urządzeniami przenośnymi i ubieralnymi, zwykle musisz nasłuchiwać ważnych zdarzeń, takich jak tworzenie elementów danych i odbieranie wiadomości.
Aby nasłuchiwać zdarzeń warstwy danych, masz 2 możliwości:
- Utwórz usługę, która rozszerza
WearableListenerService. - Utwórz aktywność lub klasę, która implementuje interfejs
DataClient.OnDataChangedListener.
W obu przypadkach zastępujesz metody wywołania zwrotnego zdarzeń danych dla zdarzeń, które Cię interesują.
Uwaga: podczas wybierania implementacji odbiornika weź pod uwagę zużycie baterii przez aplikację. Usługa WearableListenerService jest zarejestrowana w pliku manifestu aplikacji i może uruchomić aplikację, jeśli nie jest ona jeszcze uruchomiona. Jeśli musisz nasłuchiwać zdarzeń tylko wtedy, gdy aplikacja jest już uruchomiona (co często ma miejsce w przypadku aplikacji interaktywnych), nie używaj WearableListenerService. Zamiast tego zarejestruj odbiornik na żywo. Użyj np. metody addListener klasy
DataClient. Może to zmniejszyć obciążenie systemu i wykorzystanie baterii.
Korzystanie z WearableListenerService
Zwykle tworzysz instancje WearableListenerService zarówno w aplikacji na urządzenie ubieralne, jak i na urządzenie przenośne. Jeśli jednak nie interesują Cię zdarzenia danych w jednej z aplikacji, nie musisz implementować usługi w tej aplikacji.
Możesz na przykład mieć aplikację na urządzenie przenośne, która ustawia i pobiera obiekty elementów danych, oraz aplikację na urządzenia do noszenia, która nasłuchuje tych aktualizacji, aby zaktualizować interfejs. Aplikacja na urządzenia do noszenia nigdy nie aktualizuje żadnych elementów danych, więc aplikacja na urządzenie przenośne nie nasłuchuje żadnych zdarzeń danych z aplikacji na urządzenia do noszenia.
Oto niektóre zdarzenia, których możesz nasłuchiwać za pomocą WearableListenerService:
onDataChanged(): gdy element danych zostanie utworzony, usunięty lub zmieniony, system wywołuje to wywołanie zwrotne we wszystkich połączonych węzłach.onMessageReceived(): wiadomość wysłana z węzła wywołuje to wywołanie zwrotne w węźle docelowym.onCapabilityChanged(): gdy w sieci stanie się dostępna funkcja, którą reklamuje instancja Twojej aplikacji, to zdarzenie wywoła to wywołanie zwrotne. Jeśli szukasz węzła w pobliżu, możesz wysłać zapytanie doisNearby()metody węzłów podanych w wywołaniu zwrotnym.
Możesz też nasłuchiwać zdarzeń z ChannelClient.ChannelCallback, takich
jak onChannelOpened().
Wszystkie wymienione wyżej zdarzenia są wykonywane w wątku w tle, a nie w głównym wątku.
Aby utworzyć WearableListenerService:
- Utwórz klasę, która rozszerza
WearableListenerService. - Nasłuchuj zdarzeń, które Cię interesują, np.
onDataChanged(). - Zadeklaruj filtr intencji w pliku manifestu Androida, aby powiadomić system o
WearableListenerService. Ta deklaracja umożliwia systemowi powiązanie Twojej usługi w razie potrzeby.
Poniższy przykład pokazuje, jak zaimplementować 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 ) } } }
W sekcji poniżej wyjaśniono, jak używać filtra intencji z tym odbiornikiem.
Używanie filtrów z WearableListenerService
Filtr intencji dla przykładu WearableListenerService pokazanego w poprzedniej sekcji może wyglądać tak:
<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>
Filtr działania DATA_CHANGED informuje system, że Twoja aplikacja jest zainteresowana zdarzeniami warstwy danych.
W tym przykładzie zegarek nasłuchuje elementu danych /start-activity, a telefon nasłuchuje odpowiedzi na wiadomość /data-item-received (DATA_ITEM_RECEIVED_PATH).
Obowiązują standardowe reguły dopasowywania filtrów Androida. W pliku manifestu możesz określić wiele usług, wiele filtrów intencji na usługę, wiele działań na filtr i wiele sekcji danych na filtr. Filtry mogą pasować do hosta z symbolem wieloznacznym lub do konkretnego hosta. Aby dopasować hosta z symbolem wieloznacznym, użyj host="*". Aby dopasować konkretnego hosta, określ host=<node_id>.
Możesz też dopasować ścieżkę dosłowną lub prefiks ścieżki. Aby to zrobić, musisz określić symbol wieloznaczny lub konkretnego hosta. W przeciwnym razie system zignoruje określoną ścieżkę.
Więcej informacji o typach filtrów obsługiwanych przez Wear OS znajdziesz w dokumentacji referencyjnej interfejsu API
WearableListenerService.
Więcej informacji o filtrach danych i regułach dopasowywania znajdziesz w dokumentacji referencyjnej interfejsu API
dla elementu manifestu <data>.
Podczas dopasowywania filtrów intencji pamiętaj o 2 ważnych regułach:
- Jeśli dla filtra intencji nie określono schematu, system ignoruje wszystkie inne atrybuty URI.
- Jeśli dla filtra nie określono hosta, system ignoruje wszystkie atrybuty ścieżki.
Korzystanie z odbiornika na żywo
Jeśli Twoja aplikacja interesuje się zdarzeniami warstwy danych tylko wtedy, gdy użytkownik wchodzi z nią w interakcję, może nie potrzebować długotrwałej usługi do obsługi każdej zmiany danych. W takim przypadku możesz nasłuchiwać zdarzeń w aktywności.
Aby uzyskać czystsze i bezpieczniejsze rozwiązanie, użyj obserwatora cyklu życia. Dzięki użyciu
obserwatora cyklu życia przenosisz logikę rejestracji z aktywności
LifecycleResumeEvent do osobnej klasy wielokrotnego użytku, która
implementuje DefaultLifecycleObserver.
Dzięki temu aktywność jest bardziej przejrzysta i zapobiega typowym błędom, takim jak zapomnienie o wyrejestrowaniu odbiornika.
1. Utwórz odbiornik uwzględniający cykl życia
Ta klasa opakowuje DataClient.OnDataChangedListener i automatycznie
zarządza własną subskrypcją na podstawie cyklu życia aktywności.
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. Użycie w aktywności
Teraz aktywność nie musi używać LifecycleResumeEvent ani
onPause w przypadku interfejsu Wear API. Obserwatora rejestrujesz raz w LaunchedEvent (lub 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 ... } }
Dlaczego to jest lepsze:
- Czysta aktywność: usuwasz kod powtarzalny z metod cyklu życia aktywności.
- Bezpieczeństwo:
DefaultLifecycleObserverpomaga sprawdzić, czy odbiornik został usunięty, nawet jeśli aktywność zostanie nieoczekiwanie zniszczona, co zapobiega wyciekom pamięci. - Wielokrotne użycie: możesz podłączyć ten
WearDataLayerObserverdo dowolnej aktywności lub funkcji Composable bez konieczności ponownego pisania logiki rejestracji. - Oddzielenie: logika dotycząca tego, kiedy nasłuchiwać, jest oddzielona od logiki dotyczącej tego, co zrobić z danymi.
Używanie filtrów z odbiornikami na żywo
Jak wspomnieliśmy wcześniej, tak jak możesz określić filtry intencji dla
obiektów opartych na pliku manifestu WearableListenerService, możesz używać filtrów intencji
podczas rejestrowania odbiornika na żywo za pomocą interfejsu Wearable API. Te same reguły obowiązują zarówno w przypadku odbiorników na żywo opartych na interfejsie API, jak i odbiorników opartych na pliku manifestu.
Częstym wzorcem jest rejestrowanie odbiornika z określoną ścieżką lub prefiksem ścieżki
za pomocą collectAsStateWithLifecycle(). Dzięki implementacji odbiorników w ten sposób aplikacja może bardziej selektywnie odbierać zdarzenia, co poprawia jej projekt i wydajność.