处理数据层 Event

当您调用 Data Layer API 时,可以在调用完成时获得其状态。您还可以侦听因您的应用在 Android Wear 网络上任意位置做出的数据更改而引发的数据 Event。

:Wear 应用可以使用 Data Layer API 与手机应用通信,但不建议使用此 API 连接网络

等待数据层调用的状态

调用 Data Layer API 有时会返回 PendingResult,例如 putDataItem()PendingResult 创建后,操作在后台排队。如果您在此之后未执行其他操作,操作最终会以静默方式完成。不过,您通常想在操作完成后对结果进行某种处理,因此 PendingResult 允许您以同步或异步方式等待结果状态。

异步调用

如果您的代码在主界面线程上运行,请勿对 Data Layer API 进行阻塞调用。您可以通过为 PendingResult 对象添加回调函数,以异步方式运行调用,该函数在操作完成时触发:

pendingResult.setResultCallback(new ResultCallback<DataItemResult>() {
    @Override
    public void onResult(final DataItemResult result) {
        if(result.getStatus().isSuccess()) {
            Log.d(TAG, "Data item set: " + result.getDataItem().getUri());
        }
    }
});

同步调用

如果您的代码在某个后台 Service 中(在 WearableListenerService 中便是如此)的一个独立处理线程中运行,则可以阻塞调用。在此情况下,您可以调用 PendingResult 对象上的 await(),它会阻塞直至请求完成,并返回 Result 对象:

DataItemResult result = pendingResult.await();
if(result.getStatus().isSuccess()) {
    Log.d(TAG, "Data item set: " + result.getDataItem().getUri());
}

侦听数据层 Event

由于数据层跨手持式设备和穿戴式设备同步和发送数据,因此通常有必要侦听重要 Event。举例来说,此类 Event 包括创建数据项和接收消息。

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

无论做哪一个选择,您都需要重写待处理 Event 的数据 Event 回调函数。

使用 WearableListenerService

您通常同时在穿戴式设备和手持式设备应用中创建此 Service 的实例。如果您对其中一个应用中的数据 Event 不感兴趣,则无需在该特定应用中实现此 Service。

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

您可以使用 WearableListenerService 侦听的部分 Event 如下:

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

以上所有 Event 都在后台线程而不是主线程中执行。

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

  1. 创建一个扩展 WearableListenerService 的类。
  2. 侦听您感兴趣的 Event,例如 onDataChanged()
  3. 在您的 Android 清单中声明一个 Intent 过滤器,以向系统通知您的 WearableListenerService 的相关信息。此声明允许系统根据需要绑定您的 Service。

以下示例显示如何实现一个简单的 WearableListenerService

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

        GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
                .addApi(Wearable.API)
                .build();

        ConnectionResult connectionResult =
                googleApiClient.blockingConnect(30, TimeUnit.SECONDS);

        if (!connectionResult.isSuccess()) {
            Log.e(TAG, "Failed to connect to GoogleApiClient.");
            return;
        }

        // 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.MessageApi.sendMessage(googleApiClient, nodeId,
                    DATA_ITEM_RECEIVED_PATH, payload);
        }
    }
}

下一部分说明如何将 Intent 过滤器与此侦听器结合使用。

将过滤器与 WearableListenerService 结合使用

上文所示 WearableListenerService 示例的 Intent 过滤器可能类似于如下:

<service android:name=".DataLayerListenerService">
  <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 操作,使得只有特定 Event 才能唤醒或启动您的应用。这一变化提高了系统效率,并降低了电池消耗以及其他与应用有关的系统开销。在本例中,手表侦听 /start-activity 数据项,手机则侦听 /data-item-received 消息回复。

标准 Android 过滤器匹配规则适用。您可以为每个 manifest 指定多个 Service,为每个 Service 指定多个 Intent 过滤器,为每个过滤器指定多项操作,以及为每个过滤器指定多个数据节。过滤器可在通配符主机或指定主机上进行匹配。要在通配符主机上进行匹配,请使用 host="*"。要在指定主机上进行匹配,请指定 host=<node_id>

您还可以匹配文字路径或路径前缀。如果您要按路径或路径前缀匹配,您必须指定通配符或指定主机。否则,系统将忽略您指定的路径。

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

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

匹配 Intent 过滤器时,需要牢记两条重要规则:

  • 如果未给 Intent 过滤器指定架构,系统会忽略所有其他 URI 属性。
  • 如果未给过滤器指定主机,系统会忽略所有路径属性。

使用实时侦听器

如果您的应用只关心用户与应用交互时的数据层 Event,不一定需要长时间运行的 Service 来处理每个数据变化。在此类情况下,您可以通过实现下列一个或多个接口,侦听 Activity 中的 Event:

要创建侦听数据 Event 的 Activity,请执行下列操作:

  1. 实现所需接口。
  2. onCreate() 中,创建与 Data Layer API 配合使用的 GoogleApiClient 实例。
  3. onStart() 中,调用 connect(),以将客户端与 Google Play 服务相连。
  4. 与 Google Play 服务建立连接后,系统会调用 onConnected()。可在此处调用 DataApi.addListener()MessageApi.addListener()CapabilityApi.addListener(),以通知 Google Play 服务,您的 Activity 有意侦听数据层 Event。
  5. onStop() 中,使用 DataApi.removeListener()MessageApi.removeListener()CapabilityApi.removeListener() 取消注册所有侦听器。
  6. onConnected() 中添加侦听器和在 onStop() 中移除它们的替代措施是,在 Activity 的 onResume() 中添加过滤的侦听器,并在 onPause() 中将它移除,以只接收与当前应用状态有关的数据。

  7. 实现 onDataChanged() onMessageReceived()onCapabilityChanged() 函数,或来自 Channel API 侦听器函数中的函数,具体取决于您实现的接口。这些函数在主线程上调用。(不过,在 8.1 以下版本的 Google Play 服务客户端内容库中,不会在主线程上调用侦听器函数。)

下面是一个实现 DataApi.DataListener 的示例:

public class MainActivity extends Activity implements
        DataApi.DataListener, ConnectionCallbacks, OnConnectionFailedListener {

    private GoogleApiClient mGoogleApiClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addApi(Wearable.API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();
    }

    @Override
    protected void onStart() {
        super.onStart();
        if (!mResolvingError) {
            mGoogleApiClient.connect();
        }
    }

    @Override
    public void onConnected(Bundle connectionHint) {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "Connected to Google Api Service");
        }
        Wearable.DataApi.addListener(mGoogleApiClient, this);
    }

    @Override
    protected void onStop() {
        if (null != mGoogleApiClient && mGoogleApiClient.isConnected()) {
            Wearable.DataApi.removeListener(mGoogleApiClient, this);
            mGoogleApiClient.disconnect();
        }
        super.onStop();
    }

    @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 对象指定 Intent 过滤器,您还可以在通过 Wearable API 注册侦听器时使用 Intent 过滤器。同样的规则对基于 API 的侦听器和基于 manifest 的侦听器均适用。

一种常见模式是,在 Activity 的 onResume() 函数中注册具有指定路径或路径前缀的侦听器,以及在 Activity 的 onPause() 函数中移除该侦听器。以这种方式实现侦听器可以让您的应用更有选择地接收 Event,从而改善其设计和效率。