При обращении к API уровня данных вы можете получить статус вызова после его завершения. Вы также можете отслеживать события данных, возникающие в результате изменений данных, которые ваше приложение вносит в любой точке сети Wear OS by Google.
Пример эффективной работы с API уровня данных можно найти в демонстрационном приложении Android DataLayer Sample .
Дождитесь статуса вызовов уровня данных.
Вызовы API уровня данных — например, вызов метода putDataItem класса DataClient — иногда возвращают объект Task<ResultType> . Как только объект Task создан, операция ставится в очередь в фоновом режиме. Если после этого ничего не предпринимать, операция в конечном итоге завершится без предупреждения.
Однако обычно после завершения операции требуется выполнить какие-либо действия с результатом, поэтому объект Task позволяет дождаться получения результата как асинхронно, так и синхронно.
Асинхронные вызовы
Если ваш код выполняется в основном потоке пользовательского интерфейса, не используйте блокирующие вызовы к 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() { }
Другие возможности, включая цепочку выполнения различных задач, описаны в API задач .
Синхронные звонки
Если ваш код выполняется в отдельном потоке обработчика в фоновой службе, например, в WearableListenerService , используйте runBlocking для выполнения блокирующего вызова putDataItem .
Примечание: Не вызывайте эту функцию в основном потоке.
private fun Context.sendDataSync(count: Int) { // Create a data item with the path and data to be sent val putDataReq: PutDataRequest = PutDataMapRequest.create("/count").run { dataMap.putInt("count_key", count) asPutDataRequest() } // Create a task to send the data to the data layer val task: Task<DataItem> = Wearable.getDataClient(this).putDataItem(putDataReq) try { Tasks.await(task).apply { // Add your logic here } } catch (e: ExecutionException) { // TODO: Handle exception } catch (e: InterruptedException) { // TODO: Handle exception Thread.currentThread().interrupt() } }
Отслеживайте события уровня данных.
Поскольку уровень данных синхронизирует и передает данные между портативными и носимыми устройствами, обычно необходимо отслеживать важные события, такие как создание элементов данных и получение сообщений.
Для отслеживания событий уровня данных у вас есть два варианта:
- Создайте сервис, который наследует
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.
- Если для фильтра не указан хост, система игнорирует все атрибуты пути.
Используйте слушателя в режиме реального времени
Если ваше приложение реагирует на события уровня данных только тогда, когда пользователь взаимодействует с ним, ему может не понадобиться длительно работающий сервис для обработки каждого изменения данных. В таком случае вы можете прослушивать события в активности, реализовав один или несколько из следующих интерфейсов:
-
DataClient.OnDataChangedListener -
MessageClient.OnMessageReceivedListener -
CapabilityClient.OnCapabilityChangedListener -
ChannelClient.ChannelCallback
Чтобы создать действие, которое будет отслеживать события данных, выполните следующие шаги:
- Реализуйте необходимые интерфейсы.
- В методах
onCreate()илиonResume()вызовитеWearable.getDataClient(this).addListener(),MessageClient.addListener(),CapabilityClient.addListener()илиChannelClient.registerChannelCallback(), чтобы уведомить сервисы Google Play о том, что ваша активность заинтересована в событиях уровня данных. - В
onStop()илиonPause()отмените регистрацию всех слушателей с помощьюDataClient.removeListener(),MessageClient.removeListener(),CapabilityClient.removeListener()илиChannelClient.unregisterChannelCallback(). - Если активности необходимо получать только события с определенным префиксом пути, добавьте слушатель с фильтром по префиксу, чтобы получать только данные, относящиеся к текущему состоянию приложения.
- Реализуйте
onDataChanged(),onMessageReceived(),onCapabilityChanged()или методы изChannelClient.ChannelCallbackв зависимости от реализованных вами интерфейсов. Эти методы вызываются в основном потоке, или вы можете указать собственныйLooperс помощьюWearableOptions.
Вот пример реализации метода DataClient.OnDataChangedListener :
class MainActivity : Activity(), DataClient.OnDataChangedListener { public override fun onResume() { super.onResume() Wearable.getDataClient(this).addListener(this) } override fun onPause() { super.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) } } } }
Внимание: перед использованием API Wearable Data Layer убедитесь, что он доступен на устройстве; в противном случае возникнет исключение. Используйте класс GoogleApiAvailability , реализованный в Horologist .
Используйте фильтры для прослушивания в режиме реального времени.
Как уже упоминалось ранее, подобно тому, как вы можете указывать фильтры намерений для объектов WearableListenerService на основе манифеста, вы можете использовать фильтры намерений при регистрации слушателя в реальном времени через Wearable API . Те же правила применяются как к слушателям в реальном времени на основе API, так и к слушателям на основе манифеста.
Распространенный подход заключается в регистрации слушателя с определенным путем или префиксом пути в методе onResume() активности, а затем удалении слушателя в методе onPause() той же активности. Реализация слушателей таким образом позволяет приложению более избирательно получать события, улучшая его дизайн и эффективность.