同步處理永久資料

本文件說明如何在 Wear OS 裝置和 手持裝置。

直接從網路傳送及同步處理資料

建構 Wear OS 應用程式,直接與網路通訊。使用相同的 用於行動開發的 API,但保留部分 Wear OS 專屬 API 請務必留意差異

使用 Wear OS Data Layer API 同步處理資料

DataClient 會公開 API,讓元件能夠讀取或寫入 DataItem,或 Asset

您也可以在不連線至任何裝置的情況下設定資料項目和素材資源, 裝置建立網路連線後,這些裝置就會保持同步。這項資料 僅供您的應用程式使用,且僅供您的應用程式在其他裝置上存取。

  • DataItem 會同步到 Wear OS 網路中的所有裝置。 通常這應是較小型的項目;

  • 使用 Asset 轉移較大的物件,例如圖片。系統 追蹤哪些資產已轉移並執行 簡化作業

監聽服務中的事件

擴充 WearableListenerService 類別。系統會管理 基本 WearableListenerService 的生命週期,在執行時繫結至服務 必須傳送資料項目或訊息,並在無法運作時解除服務繫結 。

監聽活動中的事件

導入 OnDataChangedListener 介面。請改用這個介面 如果您只想監聽 WearableListenerService 中的變更 使用者的主動使用應用程式的次數。

轉移資料

透過藍牙傳輸二進位大型物件 (例如語音錄音) 傳送 在其他裝置上,您可以將 Asset 附加至資料項目,然後將資料項目放到複製的資料儲存庫中。

素材資源會自動處理資料快取作業,可防止系統重新傳輸,並節省藍牙頻寬。以手持裝置應用程式來說,常見的模式是將下載的圖片縮小為適合穿戴式裝置顯示的尺寸,再以素材資源形式傳輸到穿戴式裝置應用程式內。以下範例可說明這個模式。

注意:雖然資料項目的大小理論上不得超過 100 KB,但實際上可以使用更大的資料項目。針對較大的資料項目,請使用不重複的路徑分隔資料,避免讓所有資料使用同一個路徑。在很多情況下,轉移大型素材資源都會對使用者體驗造成影響,因此請測試應用程式,確定在轉移大型素材資源時能維持良好效能。

轉移素材資源

使用 Asset 類別內任一種 create...() 方法建立素材資源。將點陣圖轉換為位元組資料流,然後呼叫 createFromBytes() 建立素材資源,如以下範例所示。

Kotlin

private fun createAssetFromBitmap(bitmap: Bitmap): Asset =
    ByteArrayOutputStream().let { byteStream ->
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteStream)
        Asset.createFromBytes(byteStream.toByteArray())
    }

Java

private static Asset createAssetFromBitmap(Bitmap bitmap) {
    final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteStream);
    return Asset.createFromBytes(byteStream.toByteArray());
}

接著,使用 DataMapPutDataRequest 中的 putAsset() 方法,將素材資源附加到資料項目。然後,使用 putDataItem() 方法,如以下範例所示。

以下範例使用 PutDataRequest

Kotlin

val asset: Asset = BitmapFactory.decodeResource(resources, R.drawable.image).let { bitmap ->
    createAssetFromBitmap(bitmap)
}
val request: PutDataRequest = PutDataRequest.create("/image").apply {
    putAsset("profileImage", asset)
}
val putTask: Task<DataItem> = Wearable.getDataClient(context).putDataItem(request)

Java

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image);
Asset asset = createAssetFromBitmap(bitmap);
PutDataRequest request = PutDataRequest.create("/image");
request.putAsset("profileImage", asset);
Task<DataItem> putTask = Wearable.getDataClient(context).putDataItem(request);

以下範例使用 PutDataMapRequest

Kotlin

val asset: Asset = BitmapFactory.decodeResource(resources, R.drawable.image).let { bitmap ->
    createAssetFromBitmap(bitmap)
}
val request: PutDataRequest = PutDataMapRequest.create("/image").run {
    dataMap.putAsset("profileImage", asset)
    asPutDataRequest()
}
val putTask: Task<DataItem> = Wearable.getDataClient(context).putDataItem(request)

Java

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image);
Asset asset = createAssetFromBitmap(bitmap);
PutDataMapRequest dataMap = PutDataMapRequest.create("/image");
dataMap.getDataMap().putAsset("profileImage", asset);
PutDataRequest request = dataMap.asPutDataRequest();
Task<DataItem> putTask = Wearable.getDataClient(context).putDataItem(request);

接收素材資源

建立素材資源後,建議您在連線另一端的裝置讀取並擷取這個素材資源。以下範例說明如何實作回呼來偵測素材資源變動情形,並擷取該素材資源:

Kotlin

override fun onDataChanged(dataEvents: DataEventBuffer) {
    dataEvents
            .filter { it.type == DataEvent.TYPE_CHANGED && it.dataItem.uri.path == "/image" }
            .forEach { event ->
                val bitmap: Bitmap? = DataMapItem.fromDataItem(event.dataItem)
                        .dataMap.getAsset("profileImage")
                        .let { asset -> loadBitmapFromAsset(asset) }
                // Do something with the bitmap
            }
}

fun loadBitmapFromAsset(asset: Asset): Bitmap? {
    // Convert asset into a file descriptor and block until it's ready
    val assetInputStream: InputStream? =
            Tasks.await(Wearable.getDataClient(context).getFdForAsset(asset))
            ?.inputStream

    return assetInputStream?.let { inputStream ->
        // Decode the stream into a bitmap
        BitmapFactory.decodeStream(inputStream)
    } ?: run {
        Log.w(TAG, "Requested an unknown Asset.")
        null
    }
}

Java

@Override
public void onDataChanged(DataEventBuffer dataEvents) {
  for (DataEvent event : dataEvents) {
    if (event.getType() == DataEvent.TYPE_CHANGED &&
        event.getDataItem().getUri().getPath().equals("/image")) {
      DataMapItem dataMapItem = DataMapItem.fromDataItem(event.getDataItem());
      Asset profileAsset = dataMapItem.getDataMap().getAsset("profileImage");
      Bitmap bitmap = loadBitmapFromAsset(profileAsset);
      // Do something with the bitmap
    }
  }
}

public Bitmap loadBitmapFromAsset(Asset asset) {
    if (asset == null) {
        throw new IllegalArgumentException("Asset must be non-null");
    }
    // Convert asset into a file descriptor and block until it's ready
    InputStream assetInputStream =
        Tasks.await(Wearable.getDataClient(context).getFdForAsset(asset))
            .getInputStream();
    if (assetInputStream == null) {
        Log.w(TAG, "Requested an unknown Asset.");
        return null;
    }
    // Decode the stream into a bitmap
    return BitmapFactory.decodeStream(assetInputStream);
}

詳情請參閱 GitHub 上的 DataLayer 範例專案