จัดการเหตุการณ์ชั้นข้อมูลใน Wear

เมื่อเรียกใช้ Data Layer API คุณจะได้รับสถานะของการเรียกใช้เมื่อการเรียกใช้เสร็จสมบูรณ์ นอกจากนี้ คุณยังฟังเหตุการณ์ข้อมูลที่เกิดจากการเปลี่ยนแปลงข้อมูลที่แอปของคุณทำได้ทุกที่ในเครือข่าย Wear OS by Google

ดูตัวอย่างการทำงานกับ Data Layer API อย่างมีประสิทธิภาพได้ที่แอป Android DataLayer Sample

รอสถานะของการเรียกใช้ Data Layer

การเรียกใช้ Data Layer API เช่น การเรียกใช้โดยใช้เมธอด putDataItem ของคลาส DataClient บางครั้งจะแสดงผลออบเจ็กต์ Task<ResultType> ทันทีที่สร้างออบเจ็กต์ Task ระบบจะจัดคิวการดำเนินการในเบื้องหลัง หากคุณไม่ดำเนินการใดๆ เพิ่มเติมหลังจากนี้ การดำเนินการจะเสร็จสมบูรณ์โดยไม่มีการแจ้งเตือนในที่สุด

อย่างไรก็ตาม โดยปกติแล้วคุณมักต้องการทำบางอย่างกับผลลัพธ์หลังจากที่การดำเนินการเสร็จสมบูรณ์ ดังนั้นออบเจ็กต์ Task จะช่วยให้คุณรอสถานะผลลัพธ์ได้ ไม่ว่าจะเป็นแบบอะซิงโครนัสหรือซิงโครนัส

การเรียกแบบอะซิงโครนัส

หากโค้ดทำงานในเทรด UI หลัก อย่าทำการเรียกที่บล็อกไปยัง Data Layer API และใช้โครูทีนเพื่อเรียก putDataItem:

private suspend fun Context.sendDataAsync(count: Int) {
    try {
        val putDataReq: PutDataRequest = PutDataMapRequest.create("/count").run {
            dataMap.putInt("count_key", count)
            asPutDataRequest()
        }
        val dataItem = Wearable.getDataClient(this).putDataItem(putDataReq).await()
        handleDataItem(dataItem)
    } catch (e: Exception) {
        handleDataItemError(e)
    } finally {
        handleTaskComplete()
    }
}

private fun handleDataItem(dataItem: DataItem) { }
private fun handleDataItemError(exception: Exception) { }
private fun handleTaskComplete() { }

ดูความเป็นไปได้อื่นๆ ได้ที่ Task API ซึ่งรวมถึงการเชื่อมโยงการดำเนินการ ของงานต่างๆ

การโทรแบบซิงโครนัส

หากโค้ดทำงานในเธรดตัวแฮนเดิลแยกต่างหากในบริการเบื้องหลัง เช่น ใน WearableListenerService ให้ใช้ runBlocking เพื่อทำการเรียกที่บล็อกไปยัง putDataItem

หมายเหตุ: อย่าเรียกใช้ฟังก์ชันนี้ในขณะที่อยู่ในเทรดหลัก

private fun Context.sendDataSync(count: Int) {
    // Create a data item with the path and data to be sent
    val putDataReq: PutDataRequest = PutDataMapRequest.create("/count").run {
        dataMap.putInt("count_key", count)
        asPutDataRequest()
    }
    // Create a task to send the data to the data layer
    val task: Task<DataItem> = Wearable.getDataClient(this).putDataItem(putDataReq)
    try {
        Tasks.await(task).apply {
            // Add your logic here
        }
    } catch (e: ExecutionException) {
        // TODO: Handle exception
    } catch (e: InterruptedException) {
        // TODO: Handle exception
        Thread.currentThread().interrupt()
    }
}

รอรับเหตุการณ์ชั้นข้อมูล

เนื่องจากชั้นข้อมูลจะซิงค์และส่งข้อมูลในอุปกรณ์แบบพกพาและอุปกรณ์ที่สวมใส่ได้ คุณจึงมักจะต้องรอฟังเหตุการณ์สำคัญ เช่น การสร้างรายการข้อมูลและการรับข้อความ

หากต้องการรอรับเหตุการณ์ชั้นข้อมูล คุณมี 2 ตัวเลือก ดังนี้

ทั้ง 2 ตัวเลือกนี้จะลบล้างวิธีการเรียกกลับของเหตุการณ์ข้อมูลสําหรับ เหตุการณ์ที่คุณสนใจจัดการ

หมายเหตุ: โปรดพิจารณาการใช้แบตเตอรี่ของแอปเมื่อเลือกการติดตั้งใช้งาน Listener WearableListenerService จะลงทะเบียนในไฟล์ Manifest ของแอป และสามารถเปิดแอปได้หากยังไม่ได้เรียกใช้ หากคุณต้องการฟังเหตุการณ์เฉพาะเมื่อแอปทำงานอยู่แล้ว ซึ่งมักเป็นกรณีของแอปพลิเคชันแบบอินเทอร์แอกทีฟ ให้ไม่ต้องใช้ WearableListenerService แต่ให้ลงทะเบียน Listener ที่ใช้งานจริงแทน เช่น ใช้วิธี addListener ของคลาส DataClient ซึ่งจะช่วยลดภาระงานในระบบและลดการใช้แบตเตอรี่ได้

ใช้ WearableListenerService

โดยปกติแล้ว คุณจะสร้างอินสแตนซ์ของ WearableListenerService ในทั้งแอปที่ใช้กับอุปกรณ์สวมใส่และแอปที่ใช้กับอุปกรณ์ถือ อย่างไรก็ตาม หากไม่สนใจเหตุการณ์ข้อมูลในแอปใดแอปหนึ่ง คุณก็ไม่จำเป็นต้องติดตั้งใช้งานบริการในแอปนั้น

เช่น คุณอาจมีแอปแบบพกพาที่ตั้งค่าและรับออบเจ็กต์รายการข้อมูล และแอปบนอุปกรณ์ที่สวมใส่ได้ซึ่งรอรับการอัปเดตเหล่านี้เพื่ออัปเดต UI แอปบนอุปกรณ์ที่สวมใส่ได้ จะไม่เคยอัปเดตรายการข้อมูลใดๆ ดังนั้นแอปบนอุปกรณ์พกพาจึงไม่ฟัง เหตุการณ์ข้อมูลใดๆ จากแอปบนอุปกรณ์ที่สวมใส่ได้

เหตุการณ์บางอย่างที่คุณสามารถฟังได้โดยใช้ WearableListenerService มีดังนี้

  • onDataChanged(): เมื่อใดก็ตามที่มีการสร้าง ลบ หรือ เปลี่ยนแปลงออบเจ็กต์รายการข้อมูล ระบบจะทริกเกอร์การเรียกกลับนี้ในโหนดที่เชื่อมต่อทั้งหมด
  • onMessageReceived(): ข้อความที่ส่งจากโหนดจะทริกเกอร์ การเรียกกลับนี้ในโหนดเป้าหมาย
  • onCapabilityChanged(): เมื่อความสามารถที่อินสแตนซ์ของแอปโฆษณาพร้อมใช้งานในเครือข่าย เหตุการณ์ดังกล่าวจะทริกเกอร์การเรียกกลับนี้ หากต้องการค้นหาโหนดที่อยู่ใกล้เคียง คุณสามารถค้นหาเมธอด isNearby()ของโหนดที่ระบุไว้ในการเรียกกลับ

นอกจากนี้ คุณยังฟังเหตุการณ์จาก ChannelClient.ChannelCallback ได้ด้วย เช่น onChannelOpened()

เหตุการณ์ก่อนหน้าทั้งหมดจะดำเนินการในเธรดเบื้องหลัง ไม่ใช่ในเธรดหลัก

หากต้องการสร้าง WearableListenerService ให้ทำตามขั้นตอนต่อไปนี้

  1. สร้างคลาสที่ขยาย WearableListenerService
  2. ฟังเหตุการณ์ที่คุณสนใจ เช่น onDataChanged()
  3. ประกาศตัวกรอง Intent ในไฟล์ Manifest ของ Android เพื่อแจ้งให้ระบบทราบเกี่ยวกับ WearableListenerService การประกาศนี้ช่วยให้ระบบเชื่อมโยงบริการของคุณได้ตามต้องการ

ตัวอย่างต่อไปนี้แสดงวิธีใช้ WearableListenerService

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
                    )
            }
    }
}

ส่วนต่อไปนี้จะอธิบายวิธีใช้ตัวกรอง Intent กับ Listener นี้

ใช้ตัวกรองกับ WearableListenerService

ตัวกรอง Intent สำหรับWearableListenerService ตัวอย่างที่แสดงในส่วนก่อนหน้า อาจมีลักษณะดังนี้

<service
    android:name=".snippets.datalayer.DataLayerListenerService"
    android:exported="true"
    tools:ignore="ExportedService" >
    <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>

DATA_CHANGED ตัวกรองการดำเนินการจะบอกระบบว่าแอปของคุณสนใจเหตุการณ์ใน Data Layer

ในตัวอย่างนี้ นาฬิกาจะรอรับ/start-activityรายการข้อมูล และโทรศัพท์จะรอรับข้อความ /data-item-received (DATA_ITEM_RECEIVED_PATH) ตอบกลับ

ระบบจะใช้กฎการจับคู่ตัวกรอง Android มาตรฐาน คุณระบุบริการหลายรายการ ต่อไฟล์ Manifest, ตัวกรอง Intent หลายรายการต่อบริการ, การดำเนินการหลายรายการต่อตัวกรอง และกลุ่มข้อมูลหลายรายการต่อตัวกรองได้ ตัวกรองสามารถจับคู่กับโฮสต์ไวลด์การ์ดหรือโฮสต์ที่เฉพาะเจาะจง หากต้องการจับคู่ในโฮสต์ไวลด์การ์ด ให้ใช้ host="*" หากต้องการจับคู่ในโฮสต์ที่เฉพาะเจาะจง ให้ระบุ host=<node_id>

นอกจากนี้ คุณยังจับคู่เส้นทางที่ตรงกันทุกประการหรือค่าต่อท้ายของเส้นทางได้ด้วย โดยคุณต้องระบุ สัญลักษณ์แทนหรือโฮสต์ที่เฉพาะเจาะจง มิฉะนั้น ระบบจะไม่สนใจเส้นทางที่คุณระบุ

ดูข้อมูลเพิ่มเติมเกี่ยวกับประเภทตัวกรองที่ Wear OS รองรับได้ที่เอกสารอ้างอิง API สำหรับ WearableListenerService

ดูข้อมูลเพิ่มเติมเกี่ยวกับตัวกรองข้อมูลและกฎการจับคู่ได้ในเอกสารอ้างอิง API สำหรับองค์ประกอบ Manifest ของ <data>

เมื่อจับคู่ตัวกรอง Intent โปรดคำนึงถึงกฎสำคัญ 2 ข้อต่อไปนี้

  • หากไม่ได้ระบุสคีมาสำหรับตัวกรอง Intent ระบบจะเพิกเฉยต่อแอตทริบิวต์ URI อื่นๆ ทั้งหมด
  • หากไม่ได้ระบุโฮสต์สำหรับตัวกรอง ระบบจะไม่สนใจแอตทริบิวต์เส้นทางทั้งหมด

ใช้ผู้ฟังสด

หากแอปสนใจเฉพาะเหตุการณ์ชั้นข้อมูลเมื่อผู้ใช้โต้ตอบกับแอป คุณอาจไม่จำเป็นต้องมีบริการที่ทำงานเป็นเวลานานเพื่อจัดการการเปลี่ยนแปลงข้อมูลทุกครั้ง ใน กรณีดังกล่าว คุณสามารถรอฟังเหตุการณ์ในกิจกรรมได้โดยการใช้ อินเทอร์เฟซต่อไปนี้อย่างน้อย 1 รายการ

หากต้องการสร้างกิจกรรมที่รอรับเหตุการณ์ข้อมูล ให้ทำตามขั้นตอนต่อไปนี้

  1. ใช้ส่วนติดต่อที่จำเป็น
  2. ในเมธอด onCreate() หรือ onResume() ให้เรียกใช้ Wearable.getDataClient(this).addListener(), MessageClient.addListener(), CapabilityClient.addListener() หรือ ChannelClient.registerChannelCallback() เพื่อแจ้งบริการ Google Play ว่ากิจกรรมของคุณสนใจเหตุการณ์ใน Data Layer
  3. ใน onStop() หรือ onPause() ให้ยกเลิกการลงทะเบียน Listener ด้วย DataClient.removeListener(), MessageClient.removeListener(), CapabilityClient.removeListener() หรือ ChannelClient.unregisterChannelCallback()
  4. หากกิจกรรมต้องการรับเฉพาะเหตุการณ์ที่มีคำนำหน้าเส้นทางที่เฉพาะเจาะจง ให้เพิ่ม Listener ที่มีตัวกรองคำนำหน้าเพื่อรับเฉพาะข้อมูล ที่เกี่ยวข้องกับสถานะแอปพลิเคชันปัจจุบัน
  5. ใช้ onDataChanged(), onMessageReceived(), onCapabilityChanged() หรือเมธอดจาก ChannelClient.ChannelCallback ขึ้นอยู่กับ อินเทอร์เฟซที่คุณใช้ โดยจะเรียกใช้เมธอดเหล่านี้ในเทรดหลัก หรือคุณจะระบุ Looper ที่กำหนดเองโดยใช้ WearableOptions ก็ได้

ตัวอย่างการใช้งาน DataClient.OnDataChangedListener

class MainActivity : Activity(), DataClient.OnDataChangedListener {

    public 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 ->
            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)
            }
        }
    }
}

ข้อควรระวัง: ก่อนใช้ Wearable Data Layer API ให้ตรวจสอบว่า API พร้อมใช้งานในอุปกรณ์ หรือไม่ มิฉะนั้นจะเกิดข้อยกเว้น ใช้คลาส GoogleApiAvailability ตามที่ใช้ใน Horologist

ใช้ตัวกรองกับผู้ฟังแบบเรียลไทม์

ดังที่กล่าวไว้ก่อนหน้านี้ คุณสามารถระบุตัวกรอง Intent สำหรับออบเจ็กต์ WearableListenerService ที่อิงตามไฟล์ Manifest ได้เช่นเดียวกับที่ใช้ตัวกรอง Intent เมื่อลงทะเบียน Listener แบบสดผ่าน Wearable API กฎเดียวกันนี้ มีผลกับทั้งผู้ฟังที่ใช้ API และผู้ฟังที่ใช้ไฟล์ Manifest

รูปแบบที่ใช้กันทั่วไปคือการลงทะเบียน Listener ด้วยเส้นทางหรือคำนำหน้าเส้นทางที่เฉพาะเจาะจง ในเมธอด onResume() ของกิจกรรม แล้วนำ Listener ออกใน เมธอด onPause() ของกิจกรรม การใช้ Listener ในลักษณะนี้ จะช่วยให้แอปรับเหตุการณ์ได้อย่างเลือกสรรมากขึ้น ซึ่งจะช่วยปรับปรุงการออกแบบและ ประสิทธิภาพ