Android NDK开发详解Wear之处理 Wear 上的数据层事件


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

注意:Data Layer API 只能发送消息并与 Android 手机或 Wear OS 手表同步数据。如果 Wear OS 设备已与 iOS 设备配对,Data Layer API 将无法正常运行。

因此,请不要使用 Data Layer API 作为与网络进行通信的主要方式。在 Wear OS 应用中,您应遵循与移动应用中的模式相同的模式,但二者有一些细微差异,详见 Wear OS 上的网络访问和同步。

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

等待数据层调用的状态

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

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

异步调用

如果您的代码是在主界面线程上运行的,请勿对 Data Layer 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 接口的 activity 或类。
无论选择哪一个,您都需要针对想要处理的事件,替换其数据事件回调方法。

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

使用 WearableListenerService

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

使用实时监听器

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

DataClient.OnDataChangedListener
MessageClient.OnMessageReceivedListener
CapabilityClient.OnCapabilityChangedListener
ChannelClient.ChannelCallback
如需创建用于监听数据事件的 activity,请执行以下操作:

实现所需接口。
在 onCreate() 或 onResume() 方法中,调用 Wearable.getDataClient(this).addListener()、MessageClient.addListener()、CapabilityClient.addListener() 或 ChannelClient.registerChannelCallback(),以通知 Google Play 服务您的 activity 想要监听数据层事件。
在 onStop() 或 onPause() 中,使用 DataClient.removeListener()、MessageClient.removeListener()、CapabilityClient.removeListener() 或 ChannelClient.unregisterChannelCallback() 取消注册任何监听器。
如果某个 activity 仅对具有特定路径前缀的事件感兴趣,您可以添加具有合适前缀过滤器的监听器,以便仅接收与当前应用状态有关的数据。
实现 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 {

    
    public void onResume() {
        Wearable.getDataClient(this).addListener(this);
    }

    
    protected void onPause() {
        Wearable.getDataClient(this).removeListener(this);
    }

    
    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 对象指定 intent 过滤器一样,您也可以在通过 Wearable API 注册实时监听器时使用 intent 过滤器。基于 API 的实时监听器和基于清单的监听器需遵守相同的规则。

常见的做法是在 activity 的 onResume() 方法中注册具有特定路径或路径前缀的监听器,然后在 activity 的 onPause() 方法中移除该监听器。以这种方式实现监听器,可以让您的应用更有选择性地接收事件,从而改进其设计和效率。

本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。

最后更新时间 (UTC):2023-11-20。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五一编程

程序之路有我与你同行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值