- 文档
- 教程
- 移动开发
【免费下载链接】android-training-course-in-chinese
Android官方培训课程中文版
本篇技术指南以《Android官方培训课程中文版》仓库中的 同步数据单元 一节为核心,系统讲解 Android Wear 可穿戴数据层(Wearable Data Layer API)中数据单元(DataItem)的概念、创建流程、Data Map 的使用方法,以及如何在前台 Activity 与后台 Service 中监听数据单元的变化事件。读完本文,你将掌握在手持设备与可穿戴设备之间同步键值对数据的完整方案,包括 100KB 限制内的载荷设计、路径规范、断线缓冲机制与事件回调的注册/注销生命周期管理。
Android Wear 支持多个可穿戴设备同时连接一台手持设备。为了实现跨设备的数据一致性,Google Play services 的可穿戴数据层提供了一组自动同步的数据对象,其中DataItem(数据单元)是最基础的同步载体:它被保存在一个复制的数据仓库中,系统会自动将其从手持设备同步到可穿戴设备(反之亦然),开发者无需关心底层蓝牙、Wi-Fi 或云节点的传输细节。下图展示了数据层典型的多节点网络结构:手表通过蓝牙直连手机,手机经移动网络/Wi-Fi 连接云端节点,另一块手表可通过 Wi-Fi 连接云节点,数据单元正是在这样的网络中完成同步。
数据单元(DataItem):可穿戴数据层的基础同步载体
DataItem 是系统用于在手持设备与可穿戴设备之间同步数据的接口。与不保证送达的消息不同,DataItem 是"自动同步的数据存储":只要设备处于连接状态(直连或经云节点中转),一端写入的数据最终会出现在另一端。
一个 DataItem 通常由两个核心部分组成:
| 组成 | 说明 | 限制 |
|---|---|---|
| Payload(载荷) | 一个字节数组,可用于放置任意数据,开发者需要自行完成对象的序列化与反序列化 | 大小限制在100KB之内 |
| Path(路径) | 唯一且以斜线/开头的字符串(如/path/to/data),用于唯一标识该数据项 | 必须以/开头,且在应用中唯一 |
100KB 的限制决定了 DataItem 适合承载"小数据"的同步(如计数、设置、状态值)。如果需要传输更大的二进制数据(如图像、音视频),应改用 Asset 资源 或 Channel API,它们不受 100KB 限制——这属于数据层中的另一套机制,本文不展开。
在数据层这一套 API 中,数据单元与其他同步机制各有分工(详见数据层总览 发送并同步数据):
- DataItem:需要自动同步的小型数据存储;
- MessageApi:单向消息,适合 RPC 式请求(如从手表控制手机的媒体播放器);
- Asset:附着在 DataItem 上的二进制大对象,系统自动缓存以避免重复传输;
- ChannelApi:大文件/数据流的可靠传输通道(如音乐、电影)。
通过 PutDataRequest 创建数据单元
通常不直接实现 DataItem 接口,而是通过构建请求对象交给系统,由系统返回正确实现DataItem接口的对象。标准流程如下:
- 创建一个 PutDataRequest 对象,并指定一个字符串路径以唯一确定该数据项;
- 调用
setData(byte[])方法设置载荷(Payload); - 调用
DataApi.putDataItem()方法,请求系统创建数据单元; - 当请求完成时,系统会返回正确实现
DataItem接口的对象。
对应的核心调用骨架为:
// 1. 创建请求并指定路径 PutDataRequest request = PutDataRequest.create("/path/to/data"); // 2. 设置载荷(字节数组,<= 100KB) request.setData(serializedBytes); // 3. 请求系统创建数据单元 PendingResult<DataApi.DataItemResult> pendingResult = Wearable.DataApi.putDataItem(mGoogleApiClient, request); // 4. 结果对象中携带系统返回的 DataItem(见后文 PendingResult 处理)由于直接操作原始字节需要手动处理序列化/反序列化,官方更推荐使用下面介绍的Data Map方案,将数据单元包装进一个易用的、类似Bundle的接口中。
用 Data Map 同步数据(推荐)
DataMap 类把数据单元处理为类似 Android Bundle 的形式:系统会负责对象的序列化与反序列化,开发者只需以键值对(key-value)的方式操纵数据。这也是原文档中明确给出的建议方案(见 同步数据单元)。
使用 Data Map 的五步流程
- 创建一个 PutDataMapRequest 对象,并设置数据单元的路径;
- 调用
PutDataMapRequest.getDataMap()获取可用的 Data Map 对象; - 使用
put...()系列方法(如putString()、putInt())为 Data Map 设置数据; - 调用
PutDataMapRequest.asPutDataRequest()获得PutDataRequest对象; - 调用
DataApi.putDataItem()请求系统创建数据单元。
下面来自原文档的increaseCounter()方法完整展示了如何创建一个 Data Map 并写入数据:
public class MainActivity extends Activity implements DataApi.DataListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { private static final String COUNT_KEY = "com.example.key.count"; private GoogleApiClient mGoogleApiClient; private int count = 0; ... // Create a data map and put data in it private void increaseCounter() { PutDataMapRequest putDataMapReq = PutDataMapRequest.create("/count"); putDataMapReq.getDataMap().putInt(COUNT_KEY, count++); PutDataRequest putDataReq = putDataMapReq.asPutDataRequest(); PendingResult<DataApi.DataItemResult> pendingResult = Wearable.DataApi.putDataItem(mGoogleApiClient, putDataReq); } ... }需要注意的关键点:
- 路径字符串必须唯一,这是从连接任意一端访问该数据单元的依据;路径必须以斜线
/开头。 - 如果应用需要分层数据,应设计一套适合数据结构的分层路径方案,例如
/count、/settings/preferences、/photo/0,用层级结构组织不同类别的数据单元。 - 键的命名建议使用完整限定名(如示例中的
com.example.key.count),避免在不同数据单元之间发生键冲突。
离线缓冲机制
原文档明确指出:如果手机和可穿戴设备没有连接,数据会缓冲,并在重新建立连接时同步。这是 DataItem 与 Message 的关键差异——消息在设备断开时会返回错误,而数据单元则会等待连接恢复后继续同步,因此 DataItem 非常适合承载"最终一致"的状态数据。
监听数据元事件:前台 Activity 方案
数据层连接的一端数据发生改变时,通常需要在另一端获知变化。实现一个数据单元事件的监听器即可完成。当前台 Activity 只需在用户使用应用期间感知变化时,可以实现DataApi.DataListener接口(关于监听方案的取舍,详见 处理数据层的事件)。
下面来自原文档的完整代码展示了一个监听/count路径数据变化的 Activity——当上一节例子中的 count 值发生改变时,应用会收到通知:
public class MainActivity extends Activity implements DataApi.DataListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { private static final String COUNT_KEY = "com.example.key.count"; private GoogleApiClient mGoogleApiClient; private int count = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mGoogleApiClient = new GoogleApiClient.Builder(this) .addApi(Wearable.API) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build(); } @Override protected void onResume() { super.onStart(); mGoogleApiClient.connect(); } @Override public void onConnected(Bundle bundle) { Wearable.DataApi.addListener(mGoogleApiClient, this); } @Override protected void onPause() { super.onPause(); Wearable.DataApi.removeListener(mGoogleApiClient, this); mGoogleApiClient.disconnect(); } @Override public void onDataChanged(DataEventBuffer dataEvents) { for (DataEvent event : dataEvents) { if (event.getType() == DataEvent.TYPE_CHANGED) { // DataItem 改变了 DataItem item = event.getDataItem(); if (item.getUri().getPath().compareTo("/count") == 0) { DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap(); updateCount(dataMap.getInt(COUNT_KEY)); } } else if (event.getType() == DataEvent.TYPE_DELETED) { // DataItem 删除了 } } } // 我们的更新 count 的方法 private void updateCount(int c) { ... } ... }这段代码中值得深入理解的四点:
- 监听器生命周期:Activity 实现了
DataApi.DataListener接口;在onConnected()回调中调用DataApi.addListener()把自身注册为数据单元事件监听器;在onPause()中调用DataApi.removeListener()注销监听并断开连接,避免在后台浪费连接资源。注册与注销必须成对出现。 - 事件类型:
DataEvent.TYPE_CHANGED表示数据单元被创建或修改,DataEvent.TYPE_DELETED表示数据单元被删除,需要分别处理。 - 按路径过滤:通过
item.getUri().getPath()判断事件对应的是否是自己关心的路径(示例中比较/count),避免处理无关数据。 - 读取 Data Map:
DataMapItem.fromDataItem(item).getDataMap()可以把收到的DataItem还原成DataMap,再用getInt(COUNT_KEY)按之前写入的键读取值——这一机制让"写入方用 put...()、读取方用 get...()"形成完整的键值对同步闭环。
后台监听:WearableListenerService 方案
如果应用需要在后台持续感知数据变化(即使界面不可见),则应创建一个继承自 WearableListenerService 的 Service。系统负责控制该 Service 的生命周期:当需要发送数据元或消息时与 Service 绑定,否则解除绑定。
创建步骤(详见 处理数据层的事件):
- 创建继承自
WearableListenerService的类; - 重写关心的事件回调,如
onDataChanged(); - 在 Android manifest 中声明带 intent filter 的 service,告知系统,允许系统在需要时绑定。
public class DataLayerListenerService extends WearableListenerService { private static final String TAG = "DataLayerSample"; @Override public void onDataChanged(DataEventBuffer dataEvents) { // 在此处理数据单元的创建、修改、删除事件 for (DataEvent event : dataEvents) { Uri uri = event.getDataItem().getUri(); // ... } } }对应的 manifest 声明:
<service android:name=".DataLayerListenerService"> <intent-filter> <action android:name="com.google.android.gms.wearable.BIND_LISTENER" /> </intent-filter> </service>由于GoogleApiClient是所有 Google Play services API 的入口,在 Service 中处理事件时同样需要构建客户端并连接(示例中使用了blockingConnect(30, TimeUnit.SECONDS)进行带超时的阻塞连接)。另外需要注意数据层回调权限问题:Google Play services 通过 IPC 调用回调方法,回调会继承调用进程的权限,若需在回调中执行权限操作,应使用Binder.clearCallingIdentity()/Binder.restoreCallingIdentity()重置并恢复身份。
等待数据层调用的状态:PendingResult 的异步与同步用法
调用数据层 API(如putDataItem())时,往往返回 PendingResult 对象——操作在后台排队,若不处理也会默默完成,但通常需要获知结果。有两种等待方式(详见 处理数据层的事件):
异步调用(适用于主 UI 线程,避免阻塞界面):向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):调用await()阻塞至请求完成:
DataItemResult result = pendingResult.await(); if(result.getStatus().isSuccess()) { Log.d(TAG, "Data item set: " + result.getDataItem().getUri()); }判断result.getStatus().isSuccess()是确认数据单元是否写入成功的标准做法;成功后可进一步从结果中取出系统生成的DataItem及其 URI。
连接机制与多设备同步
正如开头架构图所示,Android Wear 数据层运行在一个包含手持设备、可穿戴设备与云节点的网络中:系统会在设备间网络上设置云节点,数据不仅同步到直连设备,也会同步到经云节点(含 Wi-Fi 接入的可穿戴设备)连接的其他设备。因此在多手表场景下,一端写入的数据单元会出现在所有已连接设备上——例如手机端保存一条笔记,它会自动出现在用户的 Wear 设备上。
这一机制与 DataItem 的断线缓冲特性叠加,构成了数据层"最终一致、自动同步"的核心体验:无论设备当前经蓝牙直连、Wi-Fi 连接云节点,还是暂时离线,数据单元都会在连接可用后完成同步。
小结
围绕 同步数据单元,本文完整覆盖了:
- DataItem 的组成(Payload ≤ 100KB、唯一且以
/开头的 Path)与适用场景; - 基于
PutDataRequest.setData()的原始字节流程,以及更推荐的PutDataMapRequest+ DataMap 键值对流程; - 在前台 Activity 中通过
DataApi.DataListener监听TYPE_CHANGED/TYPE_DELETED事件,并用DataMapItem反向读取数据; - 在后台通过
WearableListenerService+ manifest intent filter 持续监听; - 通过
PendingResult的setResultCallback()与await()获取调用状态; - 多节点网络下的云节点同步与断线缓冲机制。
若需进一步探索完整数据层方案,可继续阅读仓库中同一模块的姊妹章节:访问可穿戴数据层(GoogleApiClient 的构建与连接细节)、传输资源(超出 100KB 的二进制数据)、发送与接收消息(单向 RPC 式通信)以及 处理数据层的事件(监听方案的完整对比)。
- 文档
- 教程
- 移动开发
【免费下载链接】android-training-course-in-chinese
Android官方培训课程中文版
相关推荐
LexVec Python接口详解:3行代码集成强大词向量到你的NLP系统
LexVec Python接口详解:3行代码集成强大词向量到你的NLP系统 LexVec是一款高性能的词向量模型,类似于word2vec和GloVe,在多个NL
OpenSearch 1.3.4 版本发布解析:依赖安全升级、ingest-attachment 文档抽取加固与客户端断连崩溃修复
OpenSearch 1.3.4 版本发布解析:依赖安全升级、ingest attachment 文档抽取加固与客户端断连崩溃修复 本篇技术文章围绕 OpenS
文档教程移动开发Android 可穿戴应用开发实战:从 Notification 同步到数据层与表盘(android-training-course-in-chinese)
Android 可穿戴应用开发实战:从 Notification 同步到数据层与表盘(android training course in chinese) 本
文档教程移动开发
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考