Android Wear开发 - 数据通讯 - 第三节 : 事件处理
http://developer.android.com/training/wearables/data-layer/events.html
以下是本人在学习官方开发文档时的笔记,主要是翻译为主,并在中间会插入一些自己的总结与研究,希望对读者有所帮助.
本文分为2大部分:
Section1 : 如何获取数据通讯的结果.
Section2 : 如何监听数据层中的数据事件.
其中Section2分为2模块:
1. 继承WearableListenerService;
2. Activity实现数据接口.
Section 1 : Wait for the Status of Data Layer Calls- 等待数据操作结果
在进行数据通讯的时候,有时候会返回一个PendingResult对象,例如调用了putDataItem方法.一旦PendingResult对象被构建了,那么数据操作就会在后台队列中.你可以选择是否对这个操作结果进行处理.PendingResult对象可以让你获取到操作结果,无论是同步还是异步.
Asynchronously waiting-异步等待
若你是在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());
}
}
});
Synchronously waiting-同步等待
若你在独立的后台服务进程中进行数据操作,那么可以使用同步等待的方式来处理操作结果,在获取到处理结果前都会阻塞住进程.
DataItemResult result = pendingResult.await();
if(result.getStatus().isSuccess()) {
Log.d(TAG, "Data item set: " + result.getDataItem().getUri());
}
Section 2 : Listen for Data Layer Events- 监听数据层事件
因为在手机和手表的数据通讯同步的,所以通常需要监听一些重要的事件,如数据创建,消息接收,通讯的连接.
监听数据通讯,可以通过以下两种方式实现:
- 创建一个继承自WearableListenerService的Service
- 创建一个实现了DataApi.DataListener数据接口的Activity
1.With a WearableListenerService
使用情景
一般而言都会在手机端和手表端都构建一个这样的子类Service. 但如果哪一端对数据事件的监听处理没什么需求,那一端则无需构建.
例如,你可以在手机端构建和传递数据给手表,手表则监听这些数据事件来更新自身界面.但手表端只是单方面的获取数据,不会对数据进行做任何修改,那么,手机端则无需监听数据通讯事件.
方法介绍
接下来是介绍WearableListenerService的一些重要事件方法:
- onDataChanged() :增,删,改,这三种事件都会调用这个接口.并且是两端都会被触发调用.→双向
- onMessageReceived():消息从一端发送,会调用另一端的接口.→单向
- onPeerConnected() , onPeerDisconnected():当两端进行连接或者断开的时候会触发.改变一端的连接状态都会调用两端的接口.→双向
实现步骤
- 继承WearableListenerService
- 监听数据通讯事件
- 在Manifest中声明,并添加intent filter监听com.google.android.gms.wearable.BIND_LISTENER这个动作
代码样例
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(, 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>
Permissions within Data Layer Callbacks
注意点
数据回调接口中的权限问题
为了回调数据事件接口,Google Play会绑定你的Service并且通过IPC的方式调用.这也导致了你的回调接口继承了调用进程的权限.
若想要在回调接口中做某些特权操作,你会发现安全验证失败了,你会发现回调接口中打印出来的进程id,是在触发回调接口的进程的id,而不是你的应用的进程.
为了解决这个问题,先调用clearCallingIdentity()来重置id,恢复为应用进程id;再执行你所需要的操作;最后再调用恢复为restoreCallingIdentity()调用者的id.
long token = Binder.clearCallingIdentity();
try {
performOperationRequiringPermissions();
} finally {
Binder.restoreCallingIdentity(token);
}
WearableListenerService的深入研究:
以下关于生命周期的测试环境是在模拟器上,在其他环境上可能略有差异.
- 生命周期 :完全由Android Wear控制 !
- 前提 : 在Manifest中进行了声明,监听了com.google.android.gms.wearable.BIND_LISTENER这个Action
- 现象 : 在手表和手机断开的情况下,安装了Demo,Service没有调用onCreate方法.当连接上,则立即调用onCreate方法.
- 生命周期流程:
连接手机 : onCreate > onPeerConnected
操作过程 : 若Service没有接收到消息,以最后一次被回调为准,约8~12秒左右后会自杀,调用onDestroy.
断开手机 : 若Service已死 : onCreate > onPeerDisconnected > onDestroy(等待8~12秒);若Service处于活跃状态,则调用后面2个方法.
- 自身已经实现了DataApi.DataListener,MessageApi.MessageListener,NodeApi.NodeListener这3个接口.
总结 :
.WearableListenerService是由Android Wear控制; .生命周期较短,在停止操作8~12秒内消亡 .不能理解为手机端和手表端的连接,而应该是理解为监听这个连接 : 因为断开两端的连接,不会立刻调用onDestroy方法 .在连接后台发生状态改变,会被立即地创建,调用回调接口,以处理应用业务
2.With a Listener Activity
方法介绍
若你的应用只是需要在用户打开时监听数据通讯事件,而不需要在后台监听数据改变,那么可以实现以下接口来实现你的需求.
- DataApi.DataListener
- MessageApi.MessageListener
- NodeApi.NodeListener
实现步骤
接下来是创建一个监听数据通讯事件的Activity
- 实现接口 : 实现上面列举的接口(根据需求来定,不需要全部都实现)
- 创建服务对象 : 在onCreate方法中创建一个GoogleApiClient对象来实现与数据通讯的连接.
- 连接服务 : 在onStart方法中调用GoogleApiClient的connect方法来连接服务
- 注册监听器 : 当GoogleApiClient连接上了服务,会回调onConnected方法,那么我们就可以在这里中注册监听器,来监听我们所关心的通讯事件.
- 反注册监听器,并断开服务 : 在onStop方法中,反注册之前注册的监听器,然后再断开GoogleApiClient服务连接.
- 实现事件回调接口 : 根据注册的监听器实现接口,处理相关的需求.
代码样例
以下是一个实现了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());
}
}
}
Android Wear开发 - 数据通讯 - 第三节 : 事件处理的更多相关文章
- Android Wear开发 - 数据通讯 - 第零节 : 打包Wear应用(手机和手表应用如何连接)
之所以将打包这一特殊的内容作为数据通讯的第零节,是因为如果没有通过配置打包的一些信息,则没有办法将手机端应用和手表端应用连接起来,则无法继续进行接下来的数据通讯的开发. 以下依然只针对Eclipse平 ...
- Android Wear开发 - 数据通讯 - 第二节 : 数据的发送与接收
本节由介绍3种数据的发送接收:1.Data Items : 比特类型数据,限制100KB以内2.Assets : 资源类型数据,大小无上限3.Message : 发送消息,触发指令 http://de ...
- Android Wear开发 - 数据通讯 - 第一节 : 连接数据层
http://developer.android.com/training/wearables/data-layer/accessing.html Accessing the Wearable Dat ...
- Android Wear开发 - 数据通讯 - 第四节 : 数据封装(解决不能序列化问题)
一. 前言 背景 一开始笔者在研究数据发送与接收的时候,看到Wear数据类DataMap除了可以put基本类型外,还有个fromBundle方法来构建一个DataMap对象.所以一口气的将原本功能上的 ...
- Android Wear开发
Android Wear从2014年3月发布到现在已经从1.0发展到2.0(目前还没正式发布).其产品定位也发化了巨大变化,因为Android Wear 1.0通讯方式只有蓝牙,限定了系统,比较依赖手 ...
- Android Wear 开发入门
大家好,我是陆嘉杰,我是一名Android开发者.我想和大家进行一些技术交流,希望越来越多的人能和我成为好朋友. 大家都知道,智能手表是下一个开发的风口,而这方面的技术又属于前沿,所以和大家分享下An ...
- IDEA搭建Android wear开发环境,Android wear,I'm comming!
随着google公布了android wear这个东西.然后又有了三星的gear,LG的G watch以及moto 360,苹果由公布了apple watch.未来可能在智能手表行业又有一场战争. 当 ...
- 想做Android Wear开发?你得先搞明白这四件事
手环和手表的腕上穿戴之争,随着Apple Watch发布和Android Wear不断完善而告一段落.尽管续航上略有缺陷,但手表以其类似手机可扩展的生态环境赢得了众多巨头的支持. Google曾透露, ...
- Android Wear开发 - 卡片通知 - 第二节 : 自定义Wear卡片样式
一.前言说明 在上一节添加Android Wear通知特性我们实现了简单的Android Wear卡片拓展,但是默认提供给我们的多张卡片只能实现简单的文字展示,如果想要自定义布局,添加图片等等,则需要 ...
随机推荐
- 2015华为机试——数字基root
题目描写叙述: 求整数的Root:给定正整数,求每位数字之和;假设和不是一位数,则反复; 输入:输入随意一个或多个整数 输出:输出各位数字之和,直到和为个位数为止(输入异常,则返回-1),多行,每行相 ...
- android 01
安卓开源(就是免费),谷歌收购后推出,可以山寨(小米,三星都是安卓的山寨),ios不是开源(苹果应用要商用就要交钱).安卓3.0是平板,现在安卓至少是4.0以上,否则out了. 微软主要是系统和off ...
- Log4J2基本配置
[1]. Log4J2入门: <1>. 导入Jar包: log4j-api-2.0-beta9.jar log4j-core-2.0-beta9.jar <2>. 编写代码: ...
- Java(Android)线程池 总结
JAVA的Executors源码:(可以看出底层都是通过ThreadPoolExecutor来具体设置的~) public static ExecutorService newCachedTh ...
- php+正则将字符串中的字母数字和中文分割
原文出处 如果一段字符串中出现字母数字还有中文混排的情况,怎么才能将他们区分开呢,经过一番思索,得到了如下代码,分享给大家 如:$str="php如何将字 符串中322的字母数字sf f45 ...
- svn设置
svnserver -d -r /home/peter.mycode 如果想要开机自启动,将上述启动命令添加到:/etc/rc.local中.
- ContextSwitchDeadlock was detected Message(读取注册表时出现).
google的时候,在StackOverflow中得到个暂时解决的方法: http://stackoverflow.com/questions/2797677/contextswitchdeadloc ...
- c#中的interface abstract与virtual
interface用来声明接口1.只提供一些方法规约,不提供方法主体 如 public interface IPerson { void getName();//不包含方法主体 }2.方法不能 ...
- vim备注
① 用户path生效 在~/.bashrc中修改path,在~/.profile中source bashrc ② secureCRT着色方案 底色RGB:43 43 43 前景色RGB:221 221 ...
- JAVA 环境变量
Java是由Sun公司开发的一种应用于分布式网络环境的程序设计语言,Java语言拥有跨平台的特性,它编译的程序能够运行在多种操作系统平台上,可以实现“一次编写,到处运行”的强大功能. 工具/原料 JD ...