Đồng bộ hoá dữ liệu

Tài liệu này mô tả cách đồng bộ hoá dữ liệu giữa thiết bị Wear OS và thiết bị cầm tay.

Gửi và đồng bộ hoá dữ liệu trực tiếp từ mạng

Xây dựng các ứng dụng Wear OS để giao tiếp trực tiếp qua mạng. Sử dụng các API tương tự như cách phát triển cho thiết bị di động, nhưng hãy lưu ý một số điểm khác biệt dành riêng cho thiết bị Wear OS.

Đồng bộ hoá dữ liệu bằng API Lớp dữ liệu Wear OS

DataClient hiển thị API để các thành phần đọc hoặc ghi vào DataItem hoặc Asset.

Bạn có thể đặt các mục dữ liệu và thành phần trong khi không kết nối với bất kỳ thiết bị nào. Các tệp này được đồng bộ hoá khi thiết bị thiết lập kết nối mạng. Dữ liệu này là riêng tư đối với ứng dụng của bạn và chỉ ứng dụng của bạn mới có thể truy cập được trên các thiết bị khác.

  • DataItem được đồng bộ hoá trên mọi thiết bị trong mạng Wear OS. Chúng thường có kích thước nhỏ.

  • Sử dụng Asset để chuyển một đối tượng lớn hơn, chẳng hạn như hình ảnh. Hệ thống sẽ theo dõi những tài sản đã được chuyển và tự động loại bỏ trùng lặp.

Theo dõi các sự kiện trong dịch vụ

Mở rộng lớp WearableListenerService. Hệ thống sẽ quản lý vòng đời của WearableListenerService cơ sở, liên kết với dịch vụ khi cần gửi các mục dữ liệu hoặc thông báo và huỷ liên kết dịch vụ khi không cần hoạt động nào.

Theo dõi sự kiện trong các hoạt động

Triển khai giao diện OnDataChangedListener. Hãy sử dụng giao diện này thay vì WearableListenerService khi bạn chỉ muốn nghe các thay đổi khi người dùng đang sử dụng ứng dụng của bạn.

Chuyển dữ liệu

Để gửi các tệp nhị phân lớn qua công nghệ Bluetooth, chẳng hạn như bản ghi âm giọng nói của một thiết bị khác, bạn có thể đính kèm Asset vào một mục dữ liệu rồi đặt mục dữ liệu này vào kho dữ liệu được sao chép.

Các nội dung tự động xử lý việc lưu dữ liệu vào bộ nhớ đệm để ngăn việc truyền tải lại và tiết kiệm băng thông Bluetooth. Một mẫu kiểm thử phổ biến là để một ứng dụng cầm tay tải hình ảnh xuống, thu nhỏ kích thước phù hợp để hiển thị trên thiết bị đeo và truyền hình ảnh đó đến ứng dụng cho thiết bị đeo dưới dạng nội dung. Các ví dụ sau minh hoạ cho mẫu này.

Lưu ý: Mặc dù về mặt lý thuyết, dung lượng của các mục dữ liệu được giới hạn ở mức 100 KB nhưng trên thực tế, ta có thể sử dụng các mục dữ liệu có dung lượng lớn hơn. Đối với các mục dữ liệu lớn hơn, nhà phát triển nên phân tách dữ liệu bằng các đường dẫn riêng biệt và tránh sử dụng một đường dẫn duy nhất cho mọi dữ liệu. Việc chuyển các nội dung lớn sẽ ảnh hưởng đến trải nghiệm người dùng trong nhiều trường hợp. Vì vậy, hãy kiểm thử ứng dụng để đảm bảo ứng dụng hoạt động tốt khi chuyển các nội dung lớn.

Chuyển một nội dung

Tạo nội dung bằng một trong các phương thức create...() trong lớp Asset. Ở đây, chúng ta sẽ chuyển đổi một bitmap thành một luồng byte rồi gọi createFromBytes() để tạo nội dung như trong mẫu sau.

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

Tiếp theo, hãy đính kèm nội dung này vào mục dữ liệu bằng phương thức putAsset() trong DataMap hoặc PutDataRequest. Sau đó, đưa mục dữ liệu vào kho dữ liệu bằng phương thức putDataItem() như các mẫu sau cho thấy.

Mẫu sau đây sử dụng PutDataRequest:

KotlinJava
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)
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);

Mẫu sau đây sử dụng PutDataMapRequest:

KotlinJava
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)
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);

Nhận nội dung

Khi một nội dung được tạo, có thể bạn sẽ muốn đọc và trích xuất nội dung đó ở phía bên kia của kết nối. Dưới đây là ví dụ về cách triển khai lệnh gọi lại để phát hiện thay đổi về nội dung và trích xuất nội dung đó:

KotlinJava
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
    }
}
@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);
}

Để biết thêm thông tin, hãy xem dự án mẫu DataLayer trên GitHub.