データを同期する

このドキュメントでは、Wear OS デバイスとスマートフォンの間でデータを同期する方法について説明します。Data Layer API を使用するタイミングとインフラストラクチャを使用するタイミングについては、概要ガイドをご覧ください。

ネットワークから直接データを送信、同期する

Wear OS アプリを作成して、ネットワークと直接通信します。モバイル開発の場合と同じ API を使用できますが、Wear OS 固有の相違点に留意してください。

Wear OS Data Layer API を使用してデータを同期する

DataClient は、コンポーネントによる DataItem または Asset に対する読み取りまたは書き込みのための API を公開します。

どのデバイスにも接続していない状態でデータアイテムとアセットを設定できます。デバイスがネットワーク接続を確立すると、同期されます。このデータはアプリ専用であり、他のデバイスではアプリからのみアクセスできます。

  • DataItem は、Wear OS ネットワーク内のすべてのデバイスで同期されます。通常、これらのデータアイテムは小さいサイズです。

  • Asset を使用して、画像などの大きなオブジェクトを転送します。システムは、すでに転送されたアセットを追跡し、重複除去を自動的に実行します。

サービスでイベントをリッスンする

WearableListenerService クラスを拡張します。システムがベース WearableListenerService のライフサイクルを管理します。データアイテムやメッセージを送信する必要がある場合はサービスにバインドし、処理が不要な場合はサービスをバインド解除します。

アクティビティでイベントをリッスンする

OnDataChangedListener インターフェースを実装します。ユーザーが積極的にアプリを使用している場合にのみ変更をリッスンする場合は、WearableListenerService の代わりにこのインターフェースを使用します。

説明: Data Layer API のアセットを使用して、Android スマートフォンと Wear OS スマートウォッチ間で画像などのバイナリ ラージ オブジェクトを転送します。 keywords_public: Wear OS、Data Layer API、アセット、Bluetooth データ転送、データ同期、DataMap、PutDataRequest

データを同期する

別のデバイスからの音声録音など、大きなバイナリ オブジェクトを Bluetooth 経由で共有するために、Asset をデータアイテムにアタッチしてから、複製したデータストアにそのデータアイテムを格納できます。

注: Data Layer API でメッセージを送信し、データを同期できるのは、Android を搭載したスマートフォンまたは Wear OS スマートウォッチのみです。Wear OS デバイスが iOS デバイスとペア設定されている場合、Data Layer API は機能しません。

このため、ネットワークと通信するための主な手段としては、Data Layer API を使用しないでください。代わりに、Wear OS アプリでもスマートフォン アプリと同じパターンを使用します。ただし、Wear OS でのネットワーク アクセスと同期で説明されているように、若干の違いがあります。

アセットは、再送信を防止し、Bluetooth の帯域幅を節約するために、データのキャッシュ保存を自動的に処理します。よくあるパターンとして、スマートフォン アプリで画像をダウンロードし、それをスマートウォッチで表示するために適切なサイズに縮小して、スマートウォッチ アプリにアセットとして共有するというものがあります。次の例は、このパターンを示しています。

アセットを転送する

Asset クラスの create...() メソッドのいずれかを使用してアセットを作成します。以下のサンプルに示すように、ビットマップをバイト配列に変換し、createFromBytes() を呼び出してアセットを作成します。

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

次に、DataMap または PutDataRequestputAsset() メソッドを使用して、アセットをデータアイテムにアタッチします。その後、以下のサンプルに示すように、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 サンプル プロジェクトをご覧ください。