Google berkomitmen untuk mendorong terwujudnya keadilan ras bagi komunitas Kulit Hitam. Lihat caranya.

Menangani peristiwa Lapisan Data di perangkat Wear

Ketika melakukan panggilan ke Data Layer API, Anda bisa mendapatkan status panggilan tersebut ketika sudah selesai. Anda juga dapat memproses peristiwa data yang dihasilkan dari perubahan data yang dilakukan oleh aplikasi Anda di mana pun pada jaringan Wear OS by Google.

Catatan: Aplikasi Wear dapat berkomunikasi dengan aplikasi ponsel menggunakan Data Layer API, tetapi menghubungkan ke jaringan menggunakan API ini tidak disarankan.

Lihat referensi terkait berikut:

Menunggu status panggilan Lapisan Data

Panggilan ke Data Layer API, misalnya panggilan yang menggunakan metode putDataItem dari class DataClient, terkadang mengembalikan objek Task<ResultType>. Segera setelah objek Task dibuat, operasi akan dimasukkan ke antrean di latar belakang. Jika Anda tidak melakukan apa pun setelah ini, operasi akan diselesaikan tanpa pemberitahuan. Namun, setelah operasi ini selesai, biasanya ada hal yang ingin Anda lakukan dengan hasilnya sehingga objek Task akan membiarkan Anda menunggu status hasilnya, baik secara sinkron maupun asinkron.

Panggilan asinkron

Jika kode Anda berjalan di UI thread utama, jangan buat panggilan pemblokiran ke Data Layer API. Anda dapat menjalankan panggilan secara asinkron dengan menambahkan metode callback ke objek Task, yang akan diaktifkan ketika operasi selesai:

Kotlin

    // Using Kotlin function references
    task.addOnSuccessListener(::handleDataItem)
    task.addOnFailureListener(::handleDataItemError)
    task.addOnCompleteListener(::handleTaskComplete)
    ...
    fun handleDataItem(dataItem: DataItem) { ... }
    fun handleDataItemError(exception: Exception) { ... }
    fun handleTaskComplete(task: Task<DataItem>) { ... }
    

Java

    // Using Java 8 Lambdas.
    task.addOnSuccessListener(dataItem -> handleDataItem(dataItem));
    task.addOnFailureListener(exception -> handleDataItemError(exception));
    task.addOnCompleteListener(task -> handleTaskComplete(task));
    

Lihat Task API untuk kemungkinan lainnya, termasuk kemampuan untuk menggabungkan eksekusi beberapa tugas secara bersamaan.

Panggilan tersinkron

Jika kode Anda berjalan pada thread pengendali yang berbeda di layanan latar belakang (misalnya yang terjadi di WearableListenerService), tidak masalah jika panggilan memblokirnya. Dalam hal ini, Anda dapat memanggil Tasks.await() pada objek Task, yang melakukan pemblokiran hingga permintaan selesai dan mengembalikan objek Result:

Kotlin

    try {
        Tasks.await(dataItemTask).apply {
            Log.d(TAG, "Data item set: $uri")
        }
    }
    catch (e: ExecutionException) { ... }
    catch (e: InterruptedException) { ... }
    

Java

    try {
        DataItem item = Tasks.await(dataItemTask);
        Log.d(TAG, "Data item set: " + item.getUri());
    } catch (ExecutionException | InterruptedException e) {
      ...
    }
    

Memproses peristiwa Lapisan Data

Karena lapisan data menyinkronkan dan mengirimkan data ke perangkat genggam dan wearable, Anda biasanya perlu memproses peristiwa penting. Contoh peristiwa seperti ini mencakup pembuatan item data dan penerimaan pesan.

Untuk memproses peristiwa lapisan data, Anda memiliki dua opsi:

Dengan kedua opsi ini, Anda akan menggantikan metode callback peristiwa data untuk peristiwa yang ingin ditangani.

Catatan: Terkait penggunaan baterai, WearableListenerService terdaftar sebagai manifes aplikasi dan dapat meluncurkan aplikasi jika belum berjalan. Jika hanya perlu memproses peristiwa ketika aplikasi sudah berjalan, yang biasanya terjadi dengan aplikasi interaktif, jangan gunakan WearableListenerService. Namun, sebagai contoh, daftarkan pemroses langsung menggunakan metode addListener dari class DataClient. Hal ini dapat mengurangi beban sistem dan menghemat penggunaan baterai.

Dengan WearableListenerService

Biasanya, Anda akan membuat instance layanan ini baik dalam aplikasi wearable maupun perangkat genggam. Jika tidak tertarik dengan peristiwa data dalam salah satu aplikasi ini, Anda tidak perlu mengimplementasikan layanan dalam aplikasi tersebut.

Misalnya, Anda boleh memiliki aplikasi perangkat genggam yang menetapkan dan mendapatkan objek item data serta aplikasi wearable yang memproses update ini untuk memperbarui UI-nya. Perangkat wearable tidak pernah memperbarui item data apa pun sehingga aplikasi perangkat genggam tidak memproses peristiwa data apa pun dari aplikasi wearable.

Beberapa peristiwa yang dapat Anda proses menggunakan WearableListenerService di antaranya adalah:

  • onDataChanged(): Setiap kali objek item data dibuat, dihapus, atau diubah, sistem akan memicu callback ini pada semua node yang terhubung.
  • onMessageReceived(): Pesan yang dikirim dari node akan memicu callback ini pada node target.
  • onCapabilityChanged(): Ketika kemampuan yang disebutkan oleh instance aplikasi Anda tersedia di jaringan, peristiwa tersebut akan memicu callback ini. Jika sedang mencari node terdekat, Anda dapat meminta metode isNearby() dari node yang disediakan dalam callback.

Selain yang ada dalam daftar ini, Anda dapat memproses peristiwa dari ChannelClient.ChannelCallback, seperti onChannelOpened().

Semua peristiwa di atas dijalankan di thread latar belakang, bukan di thread utama.

Untuk membuat WearableListenerService, ikuti langkah-langkah berikut:

  1. Buat class yang memperluas WearableListenerService.
  2. Proses peristiwa yang menarik bagi Anda, seperti onDataChanged().
  3. Deklarasikan filter intent dalam manifes Android untuk memberi tahu sistem tentang WearableListenerService Anda. Deklarasi ini memungkinkan sistem mengikat layanan sesuai kebutuhan.

Contoh berikut ini menunjukkan cara mengimplementasikan WearableListenerService sederhana:

Kotlin

    private const val TAG = "DataLayerSample"
    private const val START_ACTIVITY_PATH = "/start-activity"
    private const val DATA_ITEM_RECEIVED_PATH = "/data-item-received"

    class DataLayerListenerService : WearableListenerService() {

        override fun onDataChanged(dataEvents: DataEventBuffer) {
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "onDataChanged: $dataEvents")
            }

            // Loop through the events and send a message
            // to the node that created the data item.
            dataEvents.map { it.dataItem.uri }
                    .forEach { uri ->
                        // Get the node id from the host value of the URI
                        val nodeId: String = uri.host
                        // Set the data of the message to be the bytes of the URI
                        val payload: ByteArray = uri.toString().toByteArray()

                        // Send the RPC
                        Wearable.getMessageClient(this)
                                .sendMessage(nodeId, DATA_ITEM_RECEIVED_PATH, payload)
                    }
        }
    }
    

Java

    public class DataLayerListenerService extends WearableListenerService {
        private static final String TAG = "DataLayerSample";
        private static final String START_ACTIVITY_PATH = "/start-activity";
        private static final String DATA_ITEM_RECEIVED_PATH = "/data-item-received";

        @Override
        public void onDataChanged(DataEventBuffer dataEvents) {
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "onDataChanged: " + dataEvents);
            }

            // Loop through the events and send a message
            // to the node that created the data item.
            for (DataEvent event : dataEvents) {
                Uri uri = event.getDataItem().getUri();

                // Get the node id from the host value of the URI
                String nodeId = uri.getHost();
                // Set the data of the message to be the bytes of the URI
                byte[] payload = uri.toString().getBytes();

                // Send the RPC
                Wearable.getMessageClient(this).sendMessage(
                      nodeId,  DATA_ITEM_RECEIVED_PATH, payload);
            }
        }
    }
    

Bagian berikutnya menjelaskan cara menggunakan filter intent dengan pemroses ini.

Menggunakan filter dengan WearableListenerService

Filter intent untuk contoh WearableListenerService yang ditampilkan di bagian sebelumnya mungkin terlihat seperti ini:

    <service android:name=".DataLayerListenerService">
      <intent-filter>
          <action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
          <data android:scheme="wear" android:host="*"
                   android:path="/start-activity" />
      </intent-filter>
    </service>
    

Dalam filter ini, tindakan DATA_CHANGED menggantikan tindakan BIND_LISTENER yang sebelumnya direkomendasikan sehingga hanya peristiwa tertentu yang akan mengaktifkan atau meluncurkan aplikasi Anda. Perubahan ini meningkatkan efisiensi sistem dan menghemat penggunaan baterai serta overhead lainnya terkait aplikasi Anda. Dalam contoh ini, jam tangan memproses item data /start-activity, dan ponsel memproses respons pesan /data-item-received.

Aturan pencocokan filter Android standar berlaku. Anda dapat menetapkan beberapa layanan per manifes, beberapa filter intent per layanan, beberapa tindakan per filter, dan beberapa stanza data per filter. Filter dapat mencocokkan host pengganti atau host tertentu. Untuk mencocokkan host pengganti, gunakan host="*". Untuk mencocokkan host tertentu, tetapkan host=<node_id>.

Anda juga dapat mencocokkan lokasi literal atau awalan lokasi. Jika melakukan pencocokan menurut lokasi atau awalan lokasi, Anda harus menetapkan host pengganti atau host tertentu. Jika tidak, sistem akan mengabaikan lokasi yang ditetapkan.

Untuk mengetahui informasi selengkapnya tentang jenis filter yang didukung Wear, lihat dokumentasi referensi API untuk WearableListenerService.

Untuk mengetahui informasi selengkapnya tentang aturan pencocokan dan filter data, lihat dokumentasi referensi API untuk elemen manifes data.

Ketika mencocokkan filter intent, ada dua aturan penting yang harus diingat:

  • Jika suatu skema tidak ditetapkan untuk filter intent, sistem akan mengabaikan semua atribut URI lainnya.
  • Jika tidak ada host yang ditetapkan untuk filter, sistem akan mengabaikan semua atribut lokasi.

Dengan pemroses langsung

Jika aplikasi hanya fokus pada peristiwa lapisan data ketika pengguna berinteraksi dengan aplikasi, layanan berdurasi panjang mungkin tidak diperlukan untuk menangani setiap perubahan data. Dalam hal ini, Anda dapat memproses peristiwa dalam aktivitas dengan mengimplementasikan satu atau beberapa antarmuka berikut:

Untuk membuat aktivitas yang memproses peristiwa data:

  1. Implementasikan antarmuka yang diinginkan.
  2. Di metode onCreate() atau onResume(), panggil Wearable.getDataClient(this).addListener(), MessageClient.addListener(), CapabilityClient.addListener(), atau ChannelClient.registerChannelCallback() untuk memberi tahu layanan Google Play bahwa aktivitas Anda tertarik untuk memproses peristiwa lapisan data.
  3. Di onStop() atau onPause(), batalkan pendaftaran semua pemroses dengan DataClient.removeListener(), MessageClient.removeListener(), CapabilityClient.removeListener(), atau ChannelClient.unregisterChannelCallback().
  4. Jika suatu aktivitas hanya tertarik pada peristiwa yang memiliki awalan lokasi tertentu, Anda dapat menambahkan pemroses dengan filter awalan yang sesuai agar hanya menerima data yang relevan dengan status aplikasi saat ini.
  5. Implementasikan onDataChanged(), onMessageReceived(), onCapabilityChanged(), atau metode dari ChannelClient.ChannelCallback, tergantung pada antarmuka yang Anda implementasikan. Metode ini dipanggil pada thread utama, atau Anda dapat menentukan Looper kustom menggunakan WearableOptions.

Berikut adalah contoh yang mengimplementasikan DataClient.OnDataChangedListener.

Kotlin

    class MainActivity : Activity(), DataClient.OnDataChangedListener {

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

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

        override fun onDataChanged(dataEvents: DataEventBuffer) {
            dataEvents.forEach { event ->
                if (event.type == DataEvent.TYPE_DELETED) {
                    Log.d(TAG, "DataItem deleted: " + event.dataItem.uri)
                } else if (event.type == DataEvent.TYPE_CHANGED) {
                    Log.d(TAG, "DataItem changed: " + event.dataItem.uri)
                }
            }
        }
    }
    

Java

    public class MainActivity extends Activity implements DataClient.OnDataChangedListener {

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

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

        @Override
        public void onDataChanged(DataEventBuffer dataEvents) {
            for (DataEvent event : dataEvents) {
                if (event.getType() == DataEvent.TYPE_DELETED) {
                    Log.d(TAG, "DataItem deleted: " + event.getDataItem().getUri());
                } else if (event.getType() == DataEvent.TYPE_CHANGED) {
                    Log.d(TAG, "DataItem changed: " + event.getDataItem().getUri());
                }
            }
        }
    }
    

Menggunakan filter dengan pemroses langsung

Sesuai yang telah dijelaskan sebelumnya, seperti menetapkan filter intent untuk objek WearableListenerService berbasis manifes, Anda juga dapat menggunakan filter intent saat mendaftarkan pemroses langsung melalui Wearable API. Aturan yang sama berlaku bagi pemroses langsung berbasis API dan pemroses berbasis manifes.

Pola yang cukup umum adalah mendaftarkan pemroses dengan jalur atau awalan jalur tertentu dalam metode onResume() aktivitas, dan menghapus pemroses dalam metode onPause() aktivitas. Mengimplementasikan pemroses dengan cara ini memungkinkan aplikasi Anda menerima peristiwa secara lebih selektif sehingga meningkatkan desain dan efisiensinya.