处理数据层的事件

编写:wly2014 - 原文: http://developer.android.com/training/wearables/data-layer/events.html

当做出数据层上的调用时,我们可以得到它完成后的调用状态,也可以用监听器监听到调用最终实现的改变。

等待数据层调用的状态

注意到,调用数据层API,有时会返回 PendingResult,如 putDataItem()PendingResult 一被创建,操作就会在后台排列等候。之后我们若无动作,这些操作最终会默默完成。然而,通常要处理操作完成后的结果,PendingResult 能够让我们同步或异步地等待结果。

异步调用

若代码运行在主UI线程上,不要让数据层API调用阻塞UI。我们可以增加一个回调到 PendingResult 对象来运行异步调用,该回调函数将在操作完成时触发。

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

同步调用

如果代码是运行在后台服务的一个独立的处理线程上(WearableListenerService的情况),则调用导致的阻塞没影响。在这种情况下,我们可以用 PendingResult对象调用await()),它将阻塞至请求完成,并返回一个Result对象:

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

监听数据层事件

因为数据层在手持和可穿戴设备间同步并发送数据,所以通常要监听重要事件,例如创建数据元,接收消息,或连接可穿戴设备和手机。

对于监听数据层事件,有两种选择:

通过这两种选择,为我们感兴趣的事件重写数据事件回调方法。

使用 WearableListenerService

通常,我们在手持设备和可穿戴设备上都创建该 service 的实例。如果我们不关心其中一个应用中的数据事件,就不需要在相应的应用中实现此 service。

例如,我们可以在一个手持设备应用程序上操作数据元对象,可穿戴设备应用监听这些更新来更新自身的UI。而可穿戴不更新任何数据元,所以手持设备应用不监听任何可穿戴式设备应用的数据事件。

我们可以用 WearableListenerService 监听如下事件:

  • onDataChanged()) - 当数据元对象创建,更改,删除时调用。一连接端的事件将触发两端的回调方法。
  • onMessageReceived()) - 消息从一连接端发出,在另一连接端触发此回调方法。
  • onPeerConnected()) 和 onPeerDisconnected()) - 当与手持或可穿戴设备连接或断开时调用。一连接端连接状态的改变会在两端触发此回调方法。

创建WearableListenerService,我们需要:

  1. 创建一个继承自 WearableListenerService 的类。
  2. 监听我们关心的事件,比如 onDataChanged())。
  3. 在Android manifest中声明一个intent filter,把我们的 WearableListenerService 通知给系统。这样允许系统在需要时绑定我们的 service。

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

  1. public class DataLayerListenerService extends WearableListenerService {
  2. private static final String TAG = "DataLayerSample";
  3. private static final String START_ACTIVITY_PATH = "/start-activity";
  4. private static final String DATA_ITEM_RECEIVED_PATH = "/data-item-received";
  5. @Override
  6. public void onDataChanged(DataEventBuffer dataEvents) {
  7. if (Log.isLoggable(TAG, Log.DEBUG)) {
  8. Log.d(TAG, "onDataChanged: " + dataEvents);
  9. }
  10. final List events = FreezableUtils
  11. .freezeIterable(dataEvents);
  12. GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
  13. .addApi(Wearable.API)
  14. .build();
  15. ConnectionResult connectionResult =
  16. googleApiClient.blockingConnect(30, TimeUnit.SECONDS);
  17. if (!connectionResult.isSuccess()) {
  18. Log.e(TAG, "Failed to connect to GoogleApiClient.");
  19. return;
  20. }
  21. // Loop through the events and send a message
  22. // to the node that created the data item.
  23. for (DataEvent event : events) {
  24. Uri uri = event.getDataItem().getUri();
  25. // Get the node id from the host value of the URI
  26. String nodeId = uri.getHost();
  27. // Set the data of the message to be the bytes of the URI
  28. byte[] payload = uri.toString().getBytes();
  29. // Send the RPC
  30. Wearable.MessageApi.sendMessage(googleApiClient, nodeId,
  31. DATA_ITEM_RECEIVED_PATH, payload);
  32. }
  33. }
  34. }

这是Android mainfest中相应的intent filter:

  1. <service android:name=".DataLayerListenerService">
  2. <intent-filter>
  3. <action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
  4. </intent-filter>
  5. </service>

数据层回调权限

为了在数据层事件上向我们的应用传送回调方法,Google Play services 绑定到我们的WearableListenerService,并通过IPC调用回调方法。这样的结果是,我们的回调方法继承了调用进程的权限。

如果我们想在一个回调中执行权限操作,安全检查会失败,因为回调是以调用进程的身份运行,而不是应用程序进程的身份运行。

为了解决这个问题,在进入IPC后使用 clearCallingIdentity()) 重置身份,当完成权限操作后,使用 restoreCallingIdentity()) 恢复身份:

  1. long token = Binder.clearCallingIdentity();
  2. try {
  3. performOperationRequiringPermissions();
  4. } finally {
  5. Binder.restoreCallingIdentity(token);
  6. }

使用一个Listener Activity

如果我们的应用只关心当用户与应用交互时产生的数据层事件,并且不需要一个长时间运行的 service 来处理每一次数据的改变,那么我们可以在一个 activity 中通过实现如下一个和多个接口来监听事件:

创建一个 activity 监听数据事件,需要:

  1. 实现所需的接口。
  2. onCreate(Bundle)) 中创建 GoogleApiClient 实例。
  3. onStart()) 中调用 connect()) 将客户端连接到 Google Play services。
  4. 当连接到Google Play services后,系统调用 onConnected())。这里是我们调用 DataApi.addListener()MessageApi.addListener()NodeApi.addListener(),以告知Google Play services 我们的 activity 要监听数据层事件的地方。
  5. onStop()) 中,用 DataApi.removeListener()), MessageApi.removeListener())或NodeApi.removeListener()) 注销监听。
  6. 基于我们实现的接口继而实现 onDataChanged(), onMessageReceived(), onPeerConnected()和 onPeerDisconnected()。

这是实现DataApi.DataListener的例子 :

  1. public class MainActivity extends Activity implements
  2. DataApi.DataListener, ConnectionCallbacks, OnConnectionFailedListener {
  3. private GoogleApiClient mGoogleApiClient;
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.main);
  8. mGoogleApiClient = new GoogleApiClient.Builder(this)
  9. .addApi(Wearable.API)
  10. .addConnectionCallbacks(this)
  11. .addOnConnectionFailedListener(this)
  12. .build();
  13. }
  14. @Override
  15. protected void onStart() {
  16. super.onStart();
  17. if (!mResolvingError) {
  18. mGoogleApiClient.connect();
  19. }
  20. }
  21. @Override
  22. public void onConnected(Bundle connectionHint) {
  23. if (Log.isLoggable(TAG, Log.DEBUG)) {
  24. Log.d(TAG, "Connected to Google Api Service");
  25. }
  26. Wearable.DataApi.addListener(mGoogleApiClient, this);
  27. }
  28. @Override
  29. protected void onStop() {
  30. if (null != mGoogleApiClient && mGoogleApiClient.isConnected()) {
  31. Wearable.DataApi.removeListener(mGoogleApiClient, this);
  32. mGoogleApiClient.disconnect();
  33. }
  34. super.onStop();
  35. }
  36. @Override
  37. public void onDataChanged(DataEventBuffer dataEvents) {
  38. for (DataEvent event : dataEvents) {
  39. if (event.getType() == DataEvent.TYPE_DELETED) {
  40. Log.d(TAG, "DataItem deleted: " + event.getDataItem().getUri());
  41. } else if (event.getType() == DataEvent.TYPE_CHANGED) {
  42. Log.d(TAG, "DataItem changed: " + event.getDataItem().getUri());
  43. }
  44. }
  45. }
  46. }