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() メソッドでリスナーを削除しています。

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