☰
Android 可穿戴数据层同步数据单元(DataItem)实战:DataMap 写入与监听完整指南
2026/10/7 21:11:45 网站建设 项目流程
  • 文档
  • 教程
  • 移动开发

【免费下载链接】android-training-course-in-chinese

Android官方培训课程中文版

项目地址:https://gitcode.com/gh_mirrors/an/android-training-course-in-chinese
点击查看免费下载

本篇技术指南以《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接口的对象。标准流程如下:

  1. 创建一个 PutDataRequest 对象,并指定一个字符串路径以唯一确定该数据项;
  2. 调用setData(byte[])方法设置载荷(Payload);
  3. 调用DataApi.putDataItem()方法,请求系统创建数据单元;
  4. 当请求完成时,系统会返回正确实现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 的五步流程

  1. 创建一个 PutDataMapRequest 对象,并设置数据单元的路径;
  2. 调用PutDataMapRequest.getDataMap()获取可用的 Data Map 对象;
  3. 使用put...()系列方法(如putString()、putInt())为 Data Map 设置数据;
  4. 调用PutDataMapRequest.asPutDataRequest()获得PutDataRequest对象;
  5. 调用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) { ... } ... }

这段代码中值得深入理解的四点:

  1. 监听器生命周期:Activity 实现了DataApi.DataListener接口;在onConnected()回调中调用DataApi.addListener()把自身注册为数据单元事件监听器;在onPause()中调用DataApi.removeListener()注销监听并断开连接,避免在后台浪费连接资源。注册与注销必须成对出现。
  2. 事件类型:DataEvent.TYPE_CHANGED表示数据单元被创建或修改,DataEvent.TYPE_DELETED表示数据单元被删除,需要分别处理。
  3. 按路径过滤:通过item.getUri().getPath()判断事件对应的是否是自己关心的路径(示例中比较/count),避免处理无关数据。
  4. 读取 Data Map:DataMapItem.fromDataItem(item).getDataMap()可以把收到的DataItem还原成DataMap,再用getInt(COUNT_KEY)按之前写入的键读取值——这一机制让"写入方用 put...()、读取方用 get...()"形成完整的键值对同步闭环。

后台监听:WearableListenerService 方案

如果应用需要在后台持续感知数据变化(即使界面不可见),则应创建一个继承自 WearableListenerService 的 Service。系统负责控制该 Service 的生命周期:当需要发送数据元或消息时与 Service 绑定,否则解除绑定。

创建步骤(详见 处理数据层的事件):

  1. 创建继承自WearableListenerService的类;
  2. 重写关心的事件回调,如onDataChanged();
  3. 在 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官方培训课程中文版

项目地址:https://gitcode.com/gh_mirrors/an/android-training-course-in-chinese
点击查看免费下载

相关推荐

上一篇:3分钟掌握B站缓存视频转换:m4s-converter无损合并全攻略
下一篇:3分钟极速拯救:B站缓存视频m4s转MP4完整教程

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询