http://developer.android.com/training/wearables/data-layer/events.html
以下是本人在学习官方开发文档时的笔记,主要是翻译为主,并在中间会插入一些自己的总结与研究,希望对读者有所帮助.
本文分为2大部分:
Section1 : 如何获取数据通讯的结果.
Section2 : 如何监听数据层中的数据事件.
其中Section2分为2模块:
1. 继承WearableListenerService;
2. Activity实现数据接口.
在进行数据通讯的时候,有时候会返回一个PendingResult对象,例如调用了putDataItem方法.一旦PendingResult对象被构建了,那么数据操作就会在后台队列中.你可以选择是否对这个操作结果进行处理.PendingResult对象可以让你获取到操作结果,无论是同步还是异步.
若你是在UI线程中执行数据操作,那么小心阻塞问题.在这里可以使用回调监听的方式来实现异步等待:
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());
}
}
});
若你在独立的后台服务进程中进行数据操作,那么可以使用同步等待的方式来处理操作结果,在获取到处理结果前都会阻塞住进程.
DataItemResult result = pendingResult.await();
if(result.getStatus().isSuccess()) {
Log.d(TAG, "Data item set: " + result.getDataItem().getUri());
}
因为在手机和手表的数据通讯同步的,所以通常需要监听一些重要的事件,如数据创建,消息接收,通讯的连接.
监听数据通讯,可以通过以下两种方式实现:
一般而言都会在手机端和手表端都构建一个这样的子类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);
}
final List events = FreezableUtils
.freezeIterable(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 : events) {
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);
}
}
}
注解 :
final List events = FreezableUtils .freezeIterable(dataEvents);
这里的作用是通过工具类FreezableUtils将数据对象dataEvents转换成不可修改的类型,以避免在处理数据的过程中,数据发生改变.
ConnectionResult connectionResult = googleApiClient.blockingConnect(30, TimeUnit.SECONDS);
阻塞当前线程,在30秒内获取连接状态,否则视为超时连接.因为onDataChange属于异步线程中,所以这里不会导致主线程阻塞.注意区分,这里是获取和googleApiClient的连接,而Section One中是发送数据的结果.
Manifest声明
<service android:name=".DataLayerListenerService">
<intent-filter>
<action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
</intent-filter>
</service>
注意点
数据回调接口中的权限问题
为了回调数据事件接口,Google Play会绑定你的Service并且通过IPC的方式调用.这也导致了你的回调接口继承了调用进程的权限.
若想要在回调接口中做某些特权操作,你会发现安全验证失败了,你会发现回调接口中打印出来的进程id,是在触发回调接口的进程的id,而不是你的应用的进程.
为了解决这个问题,先调用clearCallingIdentity()来重置id,恢复为应用进程id;再执行你所需要的操作;最后再调用恢复为restoreCallingIdentity()调用者的id.
long token = Binder.clearCallingIdentity();
try {
performOperationRequiringPermissions();
} finally {
Binder.restoreCallingIdentity(token);
}
以下关于生命周期的测试环境是在模拟器上,在其他环境上可能略有差异.
总结 :
1.WearableListenerService是由Android Wear控制;
2.生命周期较短,在停止操作8~12秒内消亡
3.不能理解为手机端和手表端的连接,而应该是理解为监听这个连接 : 因为断开两端的连接,不会立刻调用onDestroy方法
4.在连接后台发生状态改变,会被立即地创建,调用回调接口,以处理应用业务
若你的应用只是需要在用户打开时监听数据通讯事件,而不需要在后台监听数据改变,那么可以实现以下接口来实现你的需求.
接下来是创建一个监听数据通讯事件的Activity
以下是一个实现了DataApi.DataListener的样例:
public class MainActivity extends Activity implements
DataApi.DataListener, ConnectionCallbacks, OnConnectionFailedListener {
@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());
}
}
}