Data Layer API とデータ項目の同期

DataItem は、システムがハンドヘルドとウェアラブルの間でデータを同期するために使用するインターフェースを定義します。通常、DataItem は以下のコンポーネントで構成されます。

  • ペイロード: データを設定できるバイト配列。独自のオブジェクト シリアル化 / シリアル化解除ができます。ペイロードのサイズは 100 KB に制限されています。
  • パス: スラッシュで始まる一意の文字列(例: "/path/to/data")。

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

このため、ネットワークと通信するための主な手段としては、Data Layer API を使用しないでください。代わりに、若干の違いはあるものの、モバイルアプリと同じパターンを使用してください。

通常、DataItem を直接実装することはありません。代わりに、次の手順を行います。

  1. PutDataRequest オブジェクトを作成し、アイテムを一意に識別する文字列パスを指定します。
  2. setData() を呼び出してペイロードを設定します。
  3. 同期の遅延がユーザー エクスペリエンスに悪影響をもたらす場合は、 setUrgent() を呼び出します。
  4. DataClient クラスの putDataItem メソッドを使用して、データアイテムを作成するようシステムにリクエストします。

データアイテムをリクエストすると、システムは、DataItem インターフェースを適切に実装するオブジェクトを返します。ただし、setData() を使用して未加工のバイトを処理するのではなく、データマップを使用することをおすすめします。これにより、Bundle のようなインターフェースでデータアイテムをエクスポーズできます。

詳細については、DataLayer サンプルアプリをご覧ください。

データをデータマップと同期する

可能な場合は、DataMap クラスを使用します。このアプローチでは、Android Bundle 形式でデータアイテムを処理できるため、オブジェクトのシリアル化とシリアル化解除はシステムが行い、Key-Value ペアを含むデータの操作はデベロッパーが行うことができます。

データマップを使用する手順は次のとおりです。

  1. PutDataMapRequest オブジェクトを作成して、データアイテムのパスを設定します。

    注: 接続の両側からデータアイテムにアクセスできるように、パス文字列にはデータアイテムの一意の識別子を指定します。パスはスラッシュで始める必要があります。アプリで階層データを使用している場合は、データの構造に適合するパススキームを作成します。

  2. PutDataMapRequest.getDataMap() を呼び出して、値を設定できるデータマップを取得します。
  3. put...() メソッド(putString() など)を使用して、データマップに値を設定します。
  4. 同期の遅延がユーザー エクスペリエンスに悪影響をもたらす場合は、setUrgent() を呼び出します。
  5. PutDataMapRequest.asPutDataRequest() を呼び出して PutDataRequest オブジェクトを取得します。
  6. DataClient クラスの putDataItem メソッドを使用して、データアイテムを作成するようシステムにリクエストします。

    注: ハンドセット デバイスとウェアラブル デバイスの接続が切断された場合、接続が再確立されたときにデータのバッファリングと同期が行われます。

次の例の increaseCounter() メソッドは、データマップを作成してその中にデータを格納する方法を示しています。

Kotlin

private const val COUNT_KEY = "com.example.key.count"

class MainActivity : Activity() {

    private lateinit var dataClient: DataClient
    private var count = 0
    ...
    // Create a data map and put data in it
    private fun increaseCounter() {
        val putDataReq: PutDataRequest = PutDataMapRequest.create("/count").run {
            dataMap.putInt(COUNT_KEY, count++)
            asPutDataRequest()
        }
        val putDataTask: Task<DataItem> = dataClient.putDataItem(putDataReq)
    }
    ...
}

Java

public class MainActivity extends Activity {
    private static final String COUNT_KEY = "com.example.key.count";
    private DataClient dataClient;
    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();
        Task<DataItem> putDataTask = dataClient.putDataItem(putDataReq);
    }
  ...
}

Tasks の処理の詳細については、 リファレンス ドキュメントをご覧ください。

DataItem の優先度を設定する

DataClient API を使用すると、DataItem オブジェクトの同期の緊急リクエストを行うことができます。一般に、ユーザー デバイスのバッテリー駆動時間を改善するために、Wear OS ネットワークに対するデータアイテムの配信をシステムが遅延させることがありますが、データアイテムの同期の遅延がユーザー エクスペリエンスに悪影響をもたらす場合は、リクエストを「緊急」としてマークできます。たとえば、操作がすぐに反映されることをユーザーが期待するリモコンアプリの場合、setUrgent() を呼び出すことで、システムにデータアイテムの同期を直ちに行わせることができます。

setUrgent() を呼び出さなかった場合、システムは非緊急のデータアイテムの同期を最大で 30 分遅延させることがあります。ただし、遅延が発生したとしても、通常は数分程度で済みます。デフォルトの緊急度は「非緊急」になっているため、以前のバージョンの Wear OS API の即時同期の動作を維持したい場合は、setUrgent() を使用する必要があります。

データアイテム イベントをリッスンする

データレイヤ接続の一方でデータアイテムが変更された場合は、接続の反対側の変更をユーザーに通知します。そのためには、データアイテム イベントのリスナーを実装します。

次の例のコード スニペットは、以前の例で定義したカウンタの値が変更されたときにアプリに通知します。

Kotlin

private const val COUNT_KEY = "com.example.key.count"

class MainActivity : Activity(), DataClient.OnDataChangedListener {

    private var count = 0

    override fun onResume() {
        super.onResume()
        Wearable.getDataClient(this).addListener(this)
    }

    override fun onPause() {
        super.onPause()
        Wearable.getDataClient(this).removeListener(this)
    }

    override fun onDataChanged(dataEvents: DataEventBuffer) {
        dataEvents.forEach { event ->
            // DataItem changed
            if (event.type == DataEvent.TYPE_CHANGED) {
                event.dataItem.also { item ->
                    if (item.uri.path.compareTo("/count") == 0) {
                        DataMapItem.fromDataItem(item).dataMap.apply {
                            updateCount(getInt(COUNT_KEY))
                        }
                    }
                }
            } else if (event.type == DataEvent.TYPE_DELETED) {
                // DataItem deleted
            }
        }
    }

    // Method to update the count
    private fun updateCount(int: Int) { ... }
    ...
}

Java

public class MainActivity extends Activity implements DataClient.OnDataChangedListener {
    private static final String COUNT_KEY = "com.example.key.count";
    private int count = 0;

    @Override
    protected void onResume() {
        super.onResume();
        Wearable.getDataClient(this).addListener(this);
    }

    @Override
    protected void onPause() {
        super.onPause();
        Wearable.getDataClient(this).removeListener(this);
    }

    @Override
    public void onDataChanged(DataEventBuffer dataEvents) {
        for (DataEvent event : dataEvents) {
            if (event.getType() == DataEvent.TYPE_CHANGED) {
                // DataItem changed
                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 deleted
            }
        }
    }

    // Method to update the count
    private void updateCount(int c) { ... }
    ...
}

このアクティビティは、DataClient.OnDataChangedListener インターフェースを実装しています。また、onResume() メソッド内でアクティビティ自体をデータアイテム イベントのリスナーとして追加し、onPause() メソッドでリスナーを削除しています。画像、ビューモデル、サービスを使用した実装を確認するには、DataLayer サンプルアプリをご覧ください。

リスナーをサービスとして実装することもできます。詳細については、データレイヤー イベントをリッスンするをご覧ください。