当您调用数据层 API 时,您可以在调用完成后接收调用的状态。您还可以侦听由您的应用在 Google Wear OS 网络上的任何位置进行的数据更改所产生的数据事件。
有关有效使用数据层 API 的示例,请查看Android 数据层示例应用。
等待数据层调用的状态
对数据层 API 的调用(例如,使用DataClient
类的putDataItem
方法的调用)有时会返回一个Task<ResultType>
对象。一旦创建了Task
对象,操作就会在后台排队。如果您在此之后什么也不做,操作最终会静默完成。
但是,您通常希望在操作完成后对结果执行某些操作,因此Task
对象允许您异步或同步地等待结果状态。
异步调用
如果您的代码在主 UI 线程上运行,请不要对数据层 API 进行阻塞调用。通过向Task
对象添加一个回调方法来异步运行调用,该方法在操作完成后触发。
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));
有关其他可能性(包括链接不同任务的执行),请参阅Task API。
同步调用
如果您的代码在后台服务的单独处理程序线程上运行(例如,在WearableListenerService
中),则调用阻塞是可以的。在这种情况下,您可以对Task
对象调用Tasks.await()
,该方法会阻塞直到请求完成并返回Result
对象。以下示例显示了这一点。
注意:确保不要在主线程上调用此方法。
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) { ... }
侦听数据层事件
由于数据层在手持设备和可穿戴设备之间同步和发送数据,因此您通常需要侦听重要事件,例如创建数据项和接收消息。
要侦听数据层事件,您有两种选择:
- 创建一个扩展
WearableListenerService
的服务。 - 创建一个实现
DataClient.OnDataChangedListener
接口的活动或类。
使用这两种方法,您都可以重写您感兴趣的事件的数据事件回调方法。
注意:选择侦听器实现时,请考虑您的应用的电池使用情况。WearableListenerService
在应用的清单中注册,如果应用尚未运行,则可以启动应用。如果您只需要在应用已运行时侦听事件(对于交互式应用通常如此),则不要使用WearableListenerService
。而是注册一个实时侦听器。例如,使用DataClient
类的addListener
方法。这可以减少系统负载并减少电池使用。
使用 WearableListenerService
您通常会在可穿戴应用和手持应用中创建 WearableListenerService
的实例。但是,如果您对其中一个应用中的数据事件不感兴趣,则无需在该应用中实现该服务。
例如,您可以拥有一个设置和获取数据项对象的手持应用,以及一个侦听这些更新以更新其 UI 的可穿戴应用。可穿戴应用从不更新任何数据项,因此手持应用不会侦听来自可穿戴应用的任何数据事件。
您可以使用WearableListenerService
侦听的一些事件如下所示:
-
onDataChanged()
:每当创建、删除或更改数据项对象时,系统都会在所有连接的节点上触发此回调。 -
onMessageReceived()
:从一个节点发送的消息会在目标节点上触发此回调。 -
onCapabilityChanged()
:当您的应用实例宣传的功能在网络上可用时,该事件会触发此回调。如果您正在寻找附近的节点,您可以查询回调中提供的节点的isNearby()
方法。
您还可以侦听来自ChannelClient.ChannelCallback
的事件,例如onChannelOpened()
。
所有上述事件都在后台线程中执行,而不是在主线程中执行。
要创建WearableListenerService
,请按照以下步骤操作:
- 创建一个扩展
WearableListenerService
的类。 - 侦听您感兴趣的事件,例如
onDataChanged()
。 - 在您的 Android 清单中声明一个意图过滤器,以通知系统您的
WearableListenerService
。此声明允许系统根据需要绑定您的服务。
以下示例显示了如何实现一个简单的WearableListenerService
。
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); } } }
下一节解释如何将意图过滤器与此侦听器一起使用。
将过滤器与 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 支持的过滤器类型的更多信息,请参阅 WearableListenerService
的 API 参考文档。
有关数据过滤器和匹配规则的更多信息,请参阅<data>
清单元素的 API 参考文档。
匹配意图过滤器时,请记住两条重要规则:
- 如果未为意图过滤器指定方案,则系统会忽略所有其他 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()
注销所有侦听器。 - 如果活动只对具有特定路径前缀的事件感兴趣,则可以添加具有合适的prefix过滤器的侦听器,以仅接收与当前应用程序状态相关的數據。
- 实现
onDataChanged()
、onMessageReceived()
、onCapabilityChanged()
或ChannelClient.ChannelCallback
中的方法,具体取决于您实现的接口。这些方法在主线程上调用,或者您可以使用WearableOptions
指定自定义Looper
。
这是一个实现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()); } } } }
将过滤器与实时侦听器一起使用
如前所述,就像您可以为基于清单的WearableListenerService
对象指定意图过滤器一样,您也可以在通过Wearable API注册实时侦听器时使用意图过滤器。相同的规则适用于基于 API 的实时侦听器和基于清单的侦听器。
一个常见的模式是在活动的onResume()
方法中注册具有特定路径或路径前缀的侦听器,然后在活动的onPause()
方法中删除侦听器。以这种方式实现侦听器可以让您的应用更具选择性地接收事件,从而改进其设计和效率。