處理 Wear 資料層事件

呼叫 Data Layer API 時,您可以在呼叫完成後收到呼叫的狀態。如果應用程式在 Wear OS by Google 網路中的任何位置發生資料變更,您也可以監聽因此而產生的資料事件。

如需有效使用 Data Layer API 的範例,請參閱「Android 資料層範例」應用程式。

等待資料層呼叫的狀態

呼叫 Data Layer API (例如使用 DataClient 類別的 putDataItem 方法呼叫) 有時會傳回 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 中),請使用 runBlockingputDataItem 進行封鎖呼叫。

注意:請勿在主執行緒上呼叫此方法。

private fun Context.sendDataSync(count: Int) = runBlocking {
    val putDataReq = PutDataMapRequest.create("/count").run {
        dataMap.putInt("count_key", count)
        asPutDataRequest()
    }

    try {
        val result = Wearable.getDataClient(this@sendDataSync)
            .putDataItem(putDataReq)
            .await()
        // Logic for success
    } catch (e: Exception) {
        // Handle failure
    }
}

監聽資料層事件

由於資料層會在手持裝置和穿戴式裝置上同步處理及傳送資料,因此通常需要監聽重要事件,例如建立資料項目和接收訊息。

監聽資料層事件的方式有兩種:

使用這兩個選項時,您可以針對要處理的事件,覆寫資料事件回呼方法。

注意:選擇實作事件監聽器時,請考慮應用程式的電池用量。WearableListenerService 已在應用程式的資訊清單中註冊,如果應用程式尚未執行,則可將其啟動。如果您只需要在應用程式執行期間監聽事件 (這通常是互動式應用程式的情況),請勿使用 WearableListenerService。請改為註冊即時事件監聽器。例如,使用 DataClient 類別的 addListener 方法。這麼做可以降低系統負載並降低電池用量。

使用 WearableListenerService

您通常會一併在穿戴式應用程式與手持應用程式中建立 WearableListenerService 例項。不過,如果您對其中一個應用程式的資料事件不感興趣,就不需要在該應用程式中實作該服務。

例如,您可以建立手持應用程式來設定及取得資料項目物件,以及用來監聽這些更新,藉此更新 UI 的穿戴式應用程式。穿戴式應用程式一律不會更新任何資料項目,因此手持應用程式不會監聽來自穿戴式應用程式的任何資料事件。

您可以使用 WearableListenerService 監聽的部分事件如下:

  • onDataChanged():每當建立、刪除或變更資料項目物件時,系統會在所有連結的節點上觸發這個回呼。
  • onMessageReceived():從節點傳送的訊息會在目標節點上觸發這個回呼。
  • onCapabilityChanged():當應用程式例項所通告的能力發布到網路上,該事件就會觸發這個回呼。如要尋找附近的節點,可以查詢回呼中提供節點的 isNearby() 方法。

您也可以監聽 ChannelClient.ChannelCallback 的事件,例如 onChannelOpened()

上述所有事件都是在背景執行緒中執行,而不是在主執行緒中執行。

如要建立 WearableListenerService,請按照下列步驟操作:

  1. 建立可擴充 WearableListenerService 的類別。
  2. 監聽感興趣的事件,例如 onDataChanged()
  3. 在 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
                    )
            }
    }
}

下一節將說明如何透過這個事件監聽器使用意圖篩選器。

搭配 WearableListenerService 使用篩選器

上一節展示的 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 動作篩選器會告知系統,您的應用程式對資料層事件感興趣。

在本例中,手錶會監聽 /start-activity 資料項目,手機則會監聽 /data-item-received (DATA_ITEM_RECEIVED_PATH) 訊息回應。

請遵循標準 Android 篩選器比對規則。您可以為每個資訊清單指定多項服務、為每個服務指定多個意圖篩選器、為每個篩選器指定多個動作,以及為每個篩選器指定多個資料段落。篩選器可以透過萬用字元主機或特定主機進行比對。如要比對萬用字元主機,請使用 host="*"。如要比對特定主機,請指定 host=<node_id>

您也可以比對常值路徑或路徑前置字串。如要這麼做,您必須指定萬用字元或特定主機。否則系統會忽略您指定的路徑。

如要進一步瞭解 Wear OS 支援的篩選器類型,請參閱「WearableListenerService」的 API 參考資料說明文件。

如要進一步瞭解資料篩選器和比對規則,請參閱 <data> 資訊清單元素的 API 參考文件。

比對意圖篩選器時,請記得以下兩項重要規則:

  • 如果沒有為意圖篩選器指定配置,系統會忽略所有其他 URI 屬性。
  • 如果沒有為篩選器指定主機,系統會忽略所有路徑屬性。

使用即時監聽器

如果應用程式只重視使用者互動期間的資料層事件,則可能不需要長時間執行的服務來處理各項資料變更。在這種情況下,您可以監聽活動中的事件。

如要建議更乾淨且安全的方法,請使用 Lifecycle Observer。使用生命週期觀察器,將註冊邏輯從 Activity 的 onResume() 移至實作 DefaultLifecycleObserver 的獨立可重複使用類別。

這種做法可讓您的 Activity 保持精簡,並避免忘記取消註冊事件監聽器等常見錯誤。

1. 建立生命週期感知型接聽程式

這個類別會包裝 DataClient.OnDataChangedListener,並根據 Activity 的生命週期自動管理自己的訂閱項目。

class WearDataLayerObserver(
    private val dataClient: DataClient,
    private val onDataReceived: (DataEventBuffer) -> Unit
) : DefaultLifecycleObserver, DataClient.OnDataChangedListener {

    // Implementation of the DataClient listener
    override fun onDataChanged(dataEvents: DataEventBuffer) {
        onDataReceived(dataEvents)
    }

    // Automatically register when the Activity starts
    override fun onResume(owner: LifecycleOwner) {
        dataClient.addListener(this)
    }

    // Automatically unregister when the Activity pauses
    override fun onPause(owner: LifecycleOwner) {
        dataClient.removeListener(this)
    }
}

2. 活動記錄中的使用情況

現在,您的 Activity 不需為 Wear API 覆寫 onResume()onPause()。您只需在 onCreate() 中新增一次觀察器。

class DataLayerLifecycleActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val dataClient = Wearable.getDataClient(this)

        // Create the observer and link it to the activity's lifecycle
        val wearObserver = WearDataLayerObserver(dataClient) { dataEvents ->
            handleDataEvents(dataEvents)
        }

        lifecycle.addObserver(wearObserver)
    }

    private fun handleDataEvents(dataEvents: DataEventBuffer) {
        // ... filter and process events ...
    }
}

為何這則提示詞較好:

  • 清除活動:從活動生命週期方法中移除樣板。
  • 安全性:即使 Activity 意外遭到終止,DefaultLifecycleObserver 也能協助確認是否已移除接聽程式,避免發生記憶體洩漏問題。
  • 可重複使用:您可以將這個 WearDataLayerObserver 插入任何 Activity 或 Fragment,不必重新編寫註冊邏輯。
  • 分離:監聽時間的邏輯與資料處理邏輯分開。

搭配即時監聽器使用篩選器

如上文所述,如同您能夠針對以資訊清單為基礎的 WearableListenerService 物件指定意圖篩選器一樣,您也可以在透過 Wearable API 註冊即時事件監聽器時使用意圖篩選器。無論是以 API 為基礎的即時事件監聽器,還是以資訊清單為基礎的事件監聽器,皆須遵守相同規則。

常見的做法是使用 LifecycleObserver 註冊具有特定路徑或路徑前置字串的事件監聽器。以這種方式實作事件監聽器,可讓應用程式選擇性接收事件,從而改善其設計和效率。