Wear でデータアイテムを同期する

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

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

注: Wear アプリは Data Layer API を使用してスマートフォン アプリと通信できますが、この API を使用したネットワークへの接続は推奨されません。

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

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

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

以下の関連リソースもご覧ください。

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

可能な場合は、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 では、DataItems の緊急の同期リクエストに対処できます。一般に、ユーザー デバイスの電池寿命を改善するために、システムが Wear ネットワークへの DataItems の配信を遅らせることがありますが、DataItems の同期の遅延がユーザー エクスペリエンスに悪影響をもたらす場合は、リクエストを緊急としてマークすることができます。たとえば、ユーザーによる操作がすぐに反映されることが期待されるリモコンアプリでは、setUrgent() を呼び出すことで、システムに DataItems の同期をすぐに実行させることができます。

setUrgent() を呼び出さないと、緊急でない DataItems の同期をシステムが最大 30 分遅らせることがあります。ただし、遅延が発生したとしても、通常は数分程度になると思われます。デフォルトの緊急度は、現在は緊急でないため、以前のバージョンの Wear 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
                }
            }
        }

        // Our 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
                }
            }
        }

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

        ...
    }
    

このアクティビティは DataClient.OnDataChangedListener インターフェースを実装しており、onResume() メソッド内でこのアクティビティ自体をデータアイテム イベントのリスナーとして追加し、onPause() メソッドでリスナーを削除しています。

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