Когда вы вызываете Data Layer API, вы можете получить статус вызова после его завершения. Вы также можете отслеживать события, связанные с изменением данных, которые ваше приложение вносит в сеть Wear OS by Google.
Пример эффективного использования Data Layer API можно найти в приложении Android DataLayer Sample.
Ожидание статуса вызовов уровня данных
Вызовы Data Layer API, например вызов с использованием метода putDataItem класса DataClient, иногда возвращают объект Task<ResultType>. Как только объект Task будет создан, операция будет поставлена в очередь в фоновом режиме.
Если вы не предпримете никаких действий, операция завершится автоматически.
Однако обычно после завершения операции с результатом нужно что-то сделать, поэтому объект Task позволяет дождаться статуса результата асинхронно или синхронно.
Асинхронные вызовы
Если ваш код выполняется в основном потоке UI, не делайте блокирующие вызовы к API уровня данных и используйте сопрограмму для вызова 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() { }
Другие возможности, в том числе объединение выполнения разных задач, описаны в Task API.
Синхронные вызовы
Если код выполняется в отдельном потоке обработчика в фоновой службе, например в WearableListenerService, используйте runBlocking, чтобы сделать блокирующий вызов putDataItem.
Примечание. Не вызывайте этот метод в основном потоке.
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 } }
Как отслеживать события уровня данных
Поскольку уровень данных синхронизирует и отправляет данные между портативным и носимым устройствами, обычно необходимо прослушивать важные события, например создание объектов данных и получение сообщений.
Чтобы прослушивать события уровня данных, можно использовать два варианта:
- Создайте сервис, который расширяет
WearableListenerService. - Создайте действие или класс, реализующий интерфейс
DataClient.OnDataChangedListener.
В обоих случаях вы переопределяете методы обратного вызова событий данных для тех событий, которые хотите обрабатывать.
Примечание. При выборе реализации прослушивателя учитывайте расход заряда батареи. WearableListenerService зарегистрирован в манифесте приложения и может запустить его, если оно ещё не запущено. Если вам нужно отслеживать события только тогда, когда приложение уже запущено (что часто бывает в интерактивных приложениях), не используйте WearableListenerService. Вместо этого зарегистрируйте слушателя трансляции. Например, используйте метод addListener класса DataClient. Это может снизить нагрузку на систему и уменьшить расход заряда батареи.
Используйте WearableListenerService
Обычно вы создаете экземпляры WearableListenerService в приложениях для носимых устройств и смартфонов. Однако если вас не интересуют события данных в одном из приложений, то реализовывать сервис в нем не нужно.
Например, вы можете создать приложение для телефона, которое задает и получает объекты элементов данных, и приложение для носимого устройства, которое отслеживает эти обновления и обновляет свой интерфейс. Приложение для носимого устройства никогда не обновляет элементы данных, поэтому приложение для телефона не отслеживает события данных из приложения для носимого устройства.
С помощью WearableListenerService можно прослушивать следующие события:
onDataChanged(): когда объект элемента данных создается, удаляется или изменяется, система запускает этот обратный вызов на всех подключенных узлах.onMessageReceived()– сообщение, отправленное из узла, запускает этот обратный вызов в целевом узле.onCapabilityChanged()– когда в сети становится доступна функция, которую рекламирует экземпляр вашего приложения, это событие вызывает обратный вызов. Если вам нужен ближайший узел, вы можете запросить методisNearby()у узлов, предоставленных в обратном вызове.
Вы также можете отслеживать события из ChannelClient.ChannelCallback, например onChannelOpened().
Все предыдущие события выполняются в фоновом потоке, а не в основном.
Чтобы создать WearableListenerService, выполните следующие действия:
- Создайте класс, который расширяет
WearableListenerService. - Прослушивайте интересующие вас события, например
onDataChanged(). - Объявите фильтр интентов в манифесте Android, чтобы уведомить систему о вашем
WearableListenerService. Эта декларация позволяет системе привязывать ваш сервис по мере необходимости.
В примере ниже показано, как реализовать 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 ) } } }
В следующем разделе рассказывается, как использовать фильтр интентов с этим прослушивателем.
Как использовать фильтры с WearableListenerService
Фильтр интентов для примера WearableListenerService, приведенного в предыдущем разделе, может выглядеть следующим образом:
<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>
Фильтр действий DATA_CHANGED сообщает системе, что ваше приложение заинтересовано в событиях уровня данных.
В этом примере часы прослушивают элемент данных /start-activity, а телефон – ответ на сообщение /data-item-received (DATA_ITEM_RECEIVED_PATH).
Применяются стандартные правила фильтрации для Android. В манифесте можно указать несколько сервисов, в каждом сервисе – несколько фильтров намерений, в каждом фильтре – несколько действий, а в каждом фильтре – несколько блоков данных. Фильтры могут соответствовать хосту с подстановочным знаком или определенному хосту. Чтобы сопоставить с подстановочным знаком хоста, используйте host="*". Чтобы сопоставить определенный хост, укажите host=<node_id>.
Вы также можете сопоставить точный путь или префикс пути. Для этого необходимо указать подстановочный знак или определенный хост. В противном случае система игнорирует указанный вами путь.
Подробную информацию о типах фильтров, поддерживаемых Wear OS, можно найти в справочной документации по API для WearableListenerService.
Дополнительную информацию о фильтрах данных и правилах сопоставления можно найти в справочной документации по API для элемента манифеста <data>.
При сопоставлении фильтров намерений следует помнить два важных правила:
- Если для фильтра интентов не указана схема, система игнорирует все остальные атрибуты URI.
- Если для фильтра не указан хост, система игнорирует все атрибуты пути.
Как использовать прослушиватель событий в реальном времени
Если приложению нужны события уровня данных только во время взаимодействия с пользователем, ему может не понадобиться долго работающая служба для обработки каждого изменения данных. В таком случае можно прослушивать события в действии.
Чтобы сделать код более понятным и безопасным, используйте наблюдатель жизненного цикла. Используя наблюдатель жизненного цикла, вы переносите логику регистрации из метода LifecycleResumeEvent класса Activity в отдельный класс, который можно использовать повторно и который реализует интерфейс DefaultLifecycleObserver.
Такой подход позволяет сделать код Activity более простым и избежать распространенных ошибок, например забыть отменить регистрацию прослушивателя.
1. Как создать слушателя с учетом жизненного цикла
Этот класс содержит DataClient.OnDataChangedListener и автоматически управляет собственной подпиской на основе жизненного цикла объекта Activity.
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. Использование в истории действий
Теперь для работы с Wear API в действиях не нужно использовать LifecycleResumeEvent или onPause. Наблюдатель регистрируется один раз в LaunchedEvent (или 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 ... } }
Преимущества:
- Очистка Activity: Вы удаляете стандартный код из методов жизненного цикла объекта activity.
- Безопасность.
DefaultLifecycleObserverпомогает убедиться, что слушатель удален, даже если объект Activity уничтожен неожиданно, предотвращая утечки памяти. - Повторное использование. Вы можете подключить
WearDataLayerObserverк любому компоненту Activity или Composable, не переписывая логику регистрации. - Разделение. Логика того, когда нужно прослушивать, отделена от логики того, что делать с данными.
Как использовать фильтры для слушателей
Как уже упоминалось, вы можете указать фильтры намерений для объектов WearableListenerService на основе манифеста, а также при регистрации активного прослушивателя с помощью Wearable API. Правила одинаковы для слушателей, созданных на основе API, и слушателей на основе манифеста.
Часто используется следующий подход: зарегистрировать прослушиватель с определенным путем или префиксом пути с помощью collectAsStateWithLifecycle(). Благодаря этому приложение будет получать только нужные события, что повысит его эффективность и улучшит дизайн.