在 Wear 上处理数据层事件

当您调用数据层 API 时,您可以在调用完成后收到调用的状态。您还可以侦听由您的应用在 Google Wear OS 网络上的任何位置进行的数据更改产生的数据事件。

有关有效使用数据层 API 的示例,请查看 Android DataLayer 示例 应用。

等待数据层调用的状态

对数据层 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在应用程序的清单中注册,如果应用程序尚未运行,则可以启动应用程序。如果您只需要在应用程序已运行时侦听事件(交互式应用程序通常如此),则不要使用WearableListenerService。而是注册一个实时侦听器。例如,使用DataClient类的addListener方法。这可以减少系统负载并降低电池使用量。

使用 WearableListenerService

您通常会在可穿戴设备和手机应用程序中都创建 WearableListenerService的实例。但是,如果您对其中一个应用程序中的数据事件不感兴趣,则无需在该应用程序中实现该服务。

例如,您可以拥有一个设置和获取数据项对象的手机应用程序,以及一个侦听这些更新以更新其 UI 的可穿戴设备应用程序。可穿戴设备应用程序永远不会更新任何数据项,因此手机应用程序不会侦听来自可穿戴设备应用程序的任何数据事件。

您可以使用WearableListenerService侦听的一些事件如下所示

  • onDataChanged():每当创建、删除或更改数据项对象时,系统都会在所有连接的节点上触发此回调。
  • onMessageReceived():从节点发送的消息会在目标节点上触发此回调。
  • onCapabilityChanged():当应用程序实例宣传的功能在网络上可用时,该事件会触发此回调。如果您正在寻找附近的节点,则可以查询回调中提供的节点的 isNearby()方法。

您还可以侦听来自ChannelClient.ChannelCallback的事件,例如onChannelOpened()

所有上述事件都在后台线程中执行,而不是在主线程中执行。

要创建WearableListenerService,请执行以下步骤

  1. 创建一个扩展WearableListenerService的类。
  2. 侦听您感兴趣的事件,例如onDataChanged()
  3. 在您的 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 属性。
  • 如果未为过滤器指定主机,则系统会忽略所有路径属性。

使用实时侦听器

如果您的应用程序只关心用户与应用程序交互时的数据层事件,则可能不需要长时间运行的服务来处理每个数据更改。在这种情况下,您可以通过实现以下一个或多个接口在活动中侦听事件

要创建一个侦听数据事件的活动,请执行以下操作

  1. 实现所需的接口。
  2. onCreate()onResume()方法中,调用Wearable.getDataClient(this).addListener()MessageClient.addListener()CapabilityClient.addListener()ChannelClient.registerChannelCallback()以通知 Google Play 服务您的活动有兴趣侦听数据层事件。
  3. onStop()onPause()中,使用DataClient.removeListener()MessageClient.removeListener()CapabilityClient.removeListener()ChannelClient.unregisterChannelCallback()取消注册任何侦听器。
  4. 如果活动只对具有特定路径前缀的事件感兴趣,则可以添加一个带有合适前缀过滤器的侦听器,以仅接收与当前应用程序状态相关的数据。
  5. 实现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()方法中删除该侦听器。以这种方式实现侦听器可以让您的应用程序更具选择性地接收事件,从而改善其设计和效率。