データを同期する

このドキュメントでは、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 スマートウォッチ間で画像などの大きなバイナリ オブジェクトを転送します。

データを同期する

別のデバイスからの音声 録音など、大きなバイナリ オブジェクトを Bluetooth 経由で共有するには、Asset をデータ アイテムにアタッチしてから、複製したデータストアにそのデータアイテムを格納します。ただし、接続された 2 つのデバイス間で 1 回限りの交換を行う場合は、より簡単な直接転送が適切かどうかを検討してください。

注: 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())
    }

次に、putAsset() メソッドを使用して、アセットをデータアイテムにアタッチします。 DataMap または PutDataRequest次に、以下のサンプルに示すように、 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
}

クラスを使用します。GoogleApiAvailability

アセットを受け取る

アセットを作成したら、通常は接続の反対側でアセットの読み取りと抽出を行います。以下の例は、アセットの変更を検出してそのアセットを抽出するコールバックの実装方法を示しています。

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 サンプル プロジェクトをご覧ください。