处理 Wear 上的数据层事件

调用 Data Layer API 时,您可以在调用完成后收到调用状态。如果您的应用在 Wear OS by Google 网络上的任何位置进行了数据更改,您还可以监听因此而引发的数据事件。

如需查看有效使用 Data Layer API 的示例,请参阅 Android DataLayer 示例应用。

等待数据层调用的状态

对 Data Layer API 的调用(例如使用 DataClient 类的 putDataItem 方法进行的调用)有时会返回 Task<ResultType> 对象。一旦创建了 Task 对象,操作便会在后台排队。 如果您在此之后不再进行任何处理,则操作最终会以静默方式完成。

不过,您通常需要在操作完成后对结果进行某种处理,因此 Task 对象允许您以异步或同步方式等待结果状态。

异步调用

如果您的代码是在主界面线程上运行的,请勿对 Data Layer 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)中的单独处理程序线程上运行,请使用 runBlockingputDataItem 进行阻塞调用。

注意:切勿在主线程上调用此方法。

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
    }
}

监听数据层事件

由于数据层会在手持式设备和穿戴式设备之间同步和发送数据,因此您通常需要监听一些重要事件,比如创建了数据项、接收了消息等。

要侦听数据层 event,您有两个选择:

无论选择哪一个,您都需要针对想要处理的事件,替换其数据事件回调方法。

注意:在选择监听器的实现方案时,请考虑应用的电池用量。WearableListenerService 是在应用的清单中注册的,可以在应用尚未运行时启动应用。如果您只需要在应用运行时监听事件(交互式应用通常就是如此),那么请不要使用 WearableListenerService。请改为注册实时监听器。例如,使用 DataClient 类的 addListener 方法。这样可以减少系统上的负载并减少电池用量。

使用 WearableListenerService

您通常需要同时在穿戴式设备应用和手持式设备应用中创建 WearableListenerService 的实例。不过,如果您对其中一个应用中的数据事件不感兴趣,则无需在相应应用中实现该服务。

例如,您可以让手持式设备应用设置并获取数据项对象,而让穿戴式设备应用监听这些更新以更新其界面。穿戴式设备应用从不更新任何数据项,因此手持式设备应用不会监听任何来自穿戴式设备应用的数据事件。

您可以使用 WearableListenerService 监听的部分事件如下:

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

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

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

如需创建 WearableListenerService,请按以下步骤操作:

  1. 创建一个扩展 WearableListenerService 的类。
  2. 监听您感兴趣的事件,例如 onDataChanged()
  3. 在 Android 清单中声明一个 intent 过滤器,以向系统通知您的 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
                    )
            }
    }
}

下一部分介绍如何将 intent 过滤器与此监听器一起使用。

对 WearableListenerService 使用过滤器

上一部分中所示 WearableListenerService 示例的 intent 过滤器可能如下所示:

<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 过滤器匹配规则。您可以为每个清单指定多项服务,为每项服务指定多个 intent 过滤器,为每个过滤器指定多项操作,并为每个过滤器指定多个数据 stanza。过滤器可以匹配通配符主机或特定主机。如需匹配通配符主机,请使用 host="*"。如需匹配特定主机,请指定 host=<node_id>

您还可以匹配字面量路径或路径前缀。为此,您必须指定通配符或特定主机。否则,系统将忽略您指定的路径。

如需详细了解 Wear OS 支持的过滤器类型,请参阅 WearableListenerService 的 API 参考文档。

如需详细了解数据过滤器和匹配规则,请参阅 <data> 清单元素的 API 参考文档。

在匹配 intent 过滤器时,请谨记两条重要规则:

  • 如果没有为 intent 过滤器指定地址协议,系统会忽略其他所有 URI 属性。
  • 如果没有为过滤器指定主机,系统会忽略所有路径属性。

使用实时监听器

如果您的应用只关心用户与应用互动时的数据层事件,则可能不需要长时间运行服务来处理每项数据更改。在这种情况下,您可以在 activity 中监听事件。

为了推荐一种更简洁、更安全的方法,请使用生命周期观察器。通过使用生命周期观察器,您可以将注册逻辑从 activity 的 onResume() 中移至实现 DefaultLifecycleObserver 的单独的可重用类中。

这种方法可让您的 activity 保持精简,并防止忘记取消注册监听器等常见 bug。

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. 在 activity 中的使用情况

现在,您的 activity 无需针对 Wear API 替换 onResume()onPause()。您只需在 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 或 Fragment,而无需重写注册逻辑。
  • 解耦:侦听时间逻辑与数据处理逻辑分离。

对实时监听器使用过滤器

如前所述,就像您可以为基于清单的 WearableListenerService 对象指定 intent 过滤器一样,您也可以在通过 Wearable API 注册实时监听器时使用 intent 过滤器。基于 API 的实时监听器和基于清单的监听器需遵守相同的规则。

一种常见模式是使用 LifecycleObserver 注册具有特定路径或路径前缀的监听器。以这种方式实现监听器可以让您的应用更有选择性地接收事件,从而改进其设计和效率。