При вызове API уровня данных вы можете получить статус вызова после его завершения. Вы также можете отслеживать события, связанные с данными, которые ваше приложение вносит в сеть Wear OS by Google.
В качестве примера эффективной работы с API Data Layer ознакомьтесь с примером приложения Android DataLayer .
Дождитесь статуса вызовов уровня данных
Вызовы API уровня данных, например, с использованием метода putDataItem
класса DataClient
, иногда возвращают объект Task<ResultType>
. Как только объект Task
создаётся, операция помещается в очередь в фоновом режиме. Если после этого не предпринимать никаких действий, операция в конечном итоге завершится без каких-либо сообщений.
Однако обычно требуется что-то сделать с результатом после завершения операции, поэтому объект Task
позволяет ожидать статус результата, как асинхронно, так и синхронно.
Асинхронные вызовы
Если ваш код выполняется в основном потоке пользовательского интерфейса, не выполняйте блокирующие вызовы к API уровня данных. Выполняйте вызовы асинхронно, добавив метод обратного вызова к объекту Task
, который срабатывает после завершения операции:
Котлин
// 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>) { ... }
Ява
// Using Java 8 Lambdas. task.addOnSuccessListener(dataItem -> handleDataItem(dataItem)); task.addOnFailureListener(exception -> handleDataItemError(exception)); task.addOnCompleteListener(task -> handleTaskComplete(task));
Другие возможности, включая цепочку выполнения различных задач, см. в API задач .
Синхронные вызовы
Если ваш код выполняется в отдельном потоке обработчика в фоновой службе, например, в WearableListenerService
, блокировка вызовов допустима. В этом случае вы можете вызвать метод Tasks.await()
для объекта Task
, который блокирует выполнение до завершения запроса и возврата объекта Result
. Это показано в следующем примере.
Примечание: не вызывайте этот метод в основном потоке.
Котлин
try { Tasks.await(dataItemTask).apply { Log.d(TAG, "Data item set: $uri") } } catch (e: ExecutionException) { ... } catch (e: InterruptedException) { ... }
Ява
try { DataItem item = Tasks.await(dataItemTask); Log.d(TAG, "Data item set: " + item.getUri()); } catch (ExecutionException | InterruptedException e) { ... }
Прослушивание событий уровня данных
Поскольку уровень данных синхронизирует и отправляет данные между портативными и носимыми устройствами, вам обычно необходимо отслеживать важные события, такие как создание элементов данных и получение сообщений.
Для прослушивания событий уровня данных у вас есть два варианта:
- Создайте службу, расширяющую
WearableListenerService
. - Создайте действие или класс, реализующий интерфейс
DataClient.OnDataChangedListener
.
При использовании обоих этих вариантов вы переопределяете методы обратного вызова событий данных для событий, которые вас интересуют в обработке.
Примечание: При выборе реализации прослушивателя учитывайте расход заряда батареи вашего приложения. Служба WearableListenerService
регистрируется в манифесте приложения и может запускать приложение, если оно ещё не запущено. Если вам нужно прослушивать события только во время работы приложения, что часто случается с интерактивными приложениями, не используйте WearableListenerService
. Вместо этого зарегистрируйте активный прослушиватель. Например, используйте метод addListener
класса DataClient
. Это может снизить нагрузку на систему и уменьшить расход заряда батареи.
Используйте WearableListenerService
Обычно экземпляры WearableListenerService
создаются как в приложениях для носимых устройств, так и в мобильных устройствах. Однако, если вас не интересуют события, связанные с данными, в одном из приложений, вам не нужно реализовывать службу в этом приложении.
Например, у вас может быть приложение для мобильного устройства, которое устанавливает и получает объекты элементов данных, и приложение для носимого устройства, которое отслеживает эти обновления для обновления своего пользовательского интерфейса. Приложение для носимого устройства никогда не обновляет элементы данных, поэтому приложение для мобильного устройства не отслеживает никакие события данных от приложения для носимого устройства.
Вот некоторые события, которые вы можете прослушивать с помощью WearableListenerService
:
-
onDataChanged()
: всякий раз, когда объект элемента данных создается, удаляется или изменяется, система запускает этот обратный вызов на всех подключенных узлах. -
onMessageReceived()
: сообщение, отправленное с узла, запускает этот обратный вызов на целевом узле. -
onCapabilityChanged()
: когда возможность, анонсируемая экземпляром вашего приложения, становится доступной в сети, это событие активирует этот обратный вызов. Если вы ищете ближайший узел, вы можете запросить методisNearby()
узлов, указанных в обратном вызове.
Вы также можете прослушивать события из ChannelClient.ChannelCallback
, например onChannelOpened()
.
Все предыдущие события выполняются в фоновом потоке, а не в основном потоке.
Чтобы создать WearableListenerService
, выполните следующие действия:
- Создайте класс, расширяющий
WearableListenerService
. - Прослушивайте события, которые вас интересуют, например
onDataChanged()
. - Объявите фильтр намерений в манифесте Android, чтобы уведомить систему о вашем
WearableListenerService
. Это объявление позволит системе при необходимости привязывать ваш сервис.
В следующем примере показано, как реализовать простой WearableListenerService
:
Котлин
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) } } }
Ява
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); } } }
В следующем разделе объясняется, как использовать фильтр намерений с этим прослушивателем.
Используйте фильтры с WearableListenerService
Фильтр намерений для примера WearableListenerService
, показанного в предыдущем разделе, может выглядеть следующим образом:
<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>
В этом фильтре действие DATA_CHANGED
заменяет ранее рекомендованное действие BIND_LISTENER
, благодаря чему только определённые события активируют или запускают ваше приложение. Это изменение повышает эффективность системы, снижает расход заряда батареи и другие накладные расходы, связанные с вашим приложением. В этом примере часы прослушивают элемент данных /start-activity
, а телефон прослушивает ответ на сообщение /data-item-received
.
Действуют стандартные правила сопоставления фильтров 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() { 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) } } } }
Ява
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()); } } } }
Внимание: Перед использованием API Wearable Data Layer убедитесь, что он доступен на устройстве; в противном случае возникнет исключение. Используйте класс GoogleApiAvailability
, как реализовано в Horologist .
Используйте фильтры с живыми слушателями
Как уже упоминалось, подобно тому, как вы можете указать фильтры намерений для объектов WearableListenerService
на основе манифеста, вы можете использовать фильтры намерений при регистрации активного прослушивателя через API Wearable . Те же правила применяются как к активным прослушивателям на основе API, так и к прослушивателям на основе манифеста.
Распространенный подход заключается в регистрации прослушивателя с определенным путем или префиксом пути в методе onResume()
активности, а затем в удалении прослушивателя в методе onPause()
этой активности. Реализация прослушивателей таким образом позволяет приложению более избирательно получать события, улучшая его дизайн и эффективность.