同步数据

本文档介绍了如何在 Wear OS 设备和手机之间同步数据。如需了解何时使用数据层 API 以及何时使用您的基础架构,请参阅概览指南

直接通过网络发送和同步数据

构建 Wear OS 应用以直接与网络通信。您可以使用用于移动开发的相同 API,但需要注意一些特定于 Wear OS 的差异。

使用 Wear OS Data Layer API 同步数据

DataClient 会提供一个 API,供组件读取 DataItemAsset 或者向其中写入数据。

可以在不连接至任何设备的情况下设置数据项和素材资源。当设备建立网络连接时,这些数据会进行同步。此数据仅供您的应用专用,并且只能由您的应用在其他设备上访问。

  • DataItem 会在 Wear OS 网络中的所有设备之间同步。 它们通常很小。

  • 使用 Asset 传输较大的对象,例如图片。系统会跟踪哪些资产已转移,并自动执行去重操作。

监听服务中的事件

扩展 WearableListenerService 类。系统会管理基本 WearableListenerService 的生命周期,在需要发送数据项或消息时绑定到该服务,而在不需要执行任何操作时取消绑定该服务。

监听 activity 中的事件

实现 OnDataChangedListener 接口。如果您只想在用户正在使用您的应用时监听相关更改,请使用此接口,而不是 WearableListenerService

description: 使用 Data Layer API 中的 Asset 在 Android 手机和 Wear OS 手表之间传输大型二进制对象(例如图片)。 keywords_public: Wear OS、Data Layer API、Asset、蓝牙数据传输、数据同步、DataMap、PutDataRequest

同步数据

如需通过蓝牙传输功能共享来自其他设备的录音等大型二进制对象,您可以将 Asset 附加到数据项,然后将数据项放入复制的数据存储区。不过,如果只是在两台已连接的设备之间进行一次性交换,请考虑是否更适合使用更简单的直接转移

注意:Data Layer API 只能通过运行 Android 的手机或 Wear OS 手表发送消息并与之同步数据。如果 Wear OS 设备与 iOS 设备配对,Data Layer API 将无法正常运行。

因此,请不要使用 Data Layer API 作为与网络进行通信的主要方式。在 Wear OS 应用中,您应遵循与手机应用相同的模式,但二者有一些细微差异,详见 Wear OS 上的网络访问和同步

资源会自动处理数据的缓存,以防止重新传输并节省蓝牙带宽。一种常见模式是,手机应用下载图片,将其缩小到适合在手表上显示的尺寸,然后将其作为资源共享给手表应用。以下示例演示了这种模式。

传输资源

使用 Asset 类中的一个 create...() 方法创建资源。将一个位图转换成字节数组,然后调用 createFromBytes() 来创建资源,如以下示例所示。

private fun createAssetFromBitmap(bitmap: Bitmap): Asset =
    ByteArrayOutputStream().let { byteStream ->
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteStream)
        Asset.createFromBytes(byteStream.toByteArray())
    }

接下来,使用 DataMapPutDataRequest 中的 putAsset() 方法将资源附加到数据项。然后,使用 putDataItem() 方法将数据项放入数据存储区,如以下示例所示。

以下示例使用 PutDataRequest

private fun Context.sendImagePutDataRequest(): Task<DataItem> {

    val asset: Asset = createAssetFromBitmap(BitmapFactory.decodeResource(resources, R.drawable.ic_walk))
    val request: PutDataRequest = PutDataRequest.create("/image").apply {
        putAsset("profileImage", asset)
    }
    val putTask: Task<DataItem> = Wearable.getDataClient(this).putDataItem(request)

    return putTask
}

以下示例使用 PutDataMapRequest

private fun Context.sendImagePutDataMapRequest(): Task<DataItem> {

    val asset: Asset = createAssetFromBitmap(BitmapFactory.decodeResource(resources, R.drawable.ic_walk))
    val request: PutDataRequest = PutDataMapRequest.create("/image").run {
        dataMap.putAsset("profileImage", asset)
        asPutDataRequest()
    }
    val putTask: Task<DataItem> = Wearable.getDataClient(this).putDataItem(request)

    return putTask
}

接收资源

创建资源后,您通常会在连接的另一端读取并提取该资源。以下示例说明了如何实现回调来检测资源变化并提取资源:

override fun onDataChanged(dataEvents: DataEventBuffer) {
    dataEvents
        .filter { it.type == DataEvent.TYPE_CHANGED && it.dataItem.uri.path == "/image" }
        .forEach { event ->
            val asset = DataMapItem.fromDataItem(event.dataItem)
                .dataMap.getAsset("profileImage")

            asset?.let { safeAsset ->
                lifecycleScope.launch {
                    val bitmap = loadBitmapFromAsset(safeAsset)
                    // Do something with the bitmap
                }
            }
        }
}

private suspend fun loadBitmapFromAsset(asset: Asset): Bitmap? = withContext(Dispatchers.IO) {
    try {
        val assetResult = Wearable.getDataClient(this@DataLayerActivity2)
            .getFdForAsset(asset)
            .await()

        assetResult?.inputStream?.use { inputStream ->
            BitmapFactory.decodeStream(inputStream)
        }
    } catch (e: Exception) {
        e.printStackTrace()
        null
    }
}

如需了解详情,请参阅 GitHub 上的 DataLayer 示例项目