Gửi và nhận tin nhắn trên Wear

Bạn gửi thông báo bằng API MessageClient và đính kèm các mục sau vào thông báo:

  • Tải trọng tuỳ ý không bắt buộc
  • Đường dẫn xác định chính xác hành động của thông báo

Không giống như trường hợp của các mục dữ liệu, không có quá trình đồng bộ hoá nào xảy ra giữa ứng dụng cầm tay và ứng dụng cho thiết bị đeo. Thông báo là cơ chế giao tiếp một chiều hữu ích cho các lệnh gọi quy trình từ xa (RPC), chẳng hạn như khi gửi thông báo đến thiết bị đeo để bắt đầu một hoạt động.

Có thể kết nối nhiều thiết bị đeo với thiết bị cầm tay của người dùng. Mỗi thiết bị được kết nối trong mạng được coi là một nút.

Với nhiều thiết bị đã kết nối, bạn phải xem xét việc nút nào sẽ nhận được thông báo. Ví dụ: trong một ứng dụng chép lời bằng giọng nói nhận dữ liệu thoại trên thiết bị đeo, hãy gửi thông báo đến một nút sử dụng nguồn và dung lượng pin để xử lý yêu cầu, chẳng hạn như một thiết bị cầm tay.

Lưu ý: Khi bạn chỉ định thông tin chi tiết về thông báo của mình, hãy xem xét khả năng sẽ có nhiều nút được kết nối. Đảm bảo tin nhắn được gửi đến các thiết bị hoặc nút mà bạn muốn.

Hãy tham khảo các ứng dụng mẫu sau để tìm hiểu ví dụ về cách sử dụng:

Gửi tin nhắn

Ứng dụng dành cho thiết bị đeo có thể cung cấp chức năng cho người dùng, chẳng hạn như chép lời bằng giọng nói. Người dùng có thể nói vào micrô của thiết bị đeo và lưu bản chép lời vào một ghi chú. Vì một thiết bị đeo thường không có nguồn và dung lượng pin cần thiết để xử lý hoạt động chép lời bằng giọng nói, ứng dụng sẽ giảm tải công việc này sang một thiết bị được kết nối có chức năng phù hợp hơn.

Phần sau đây cho bạn biết cách quảng cáo các nút thiết bị có thể xử lý các yêu cầu hoạt động, khám phá các nút có khả năng đáp ứng nhu cầu được yêu cầu, và gửi thông báo đến các nút đó.

Để chạy một hoạt động trên thiết bị cầm tay từ một thiết bị đeo, hãy sử dụng lớp MessageClient để gửi yêu cầu. Vì nhiều thiết bị đeo có thể được kết nối với thiết bị cầm tay, nên ứng dụng cho thiết bị đeo cần xác định việc một nút đã kết nối có thể khởi chạy hoạt động. Trong ứng dụng cầm tay, hãy quảng cáo về việc nút chạy trên đó cung cấp những tính năng cụ thể.

Để quảng cáo các tính năng của ứng dụng cầm tay, hãy làm như sau:

  1. Tạo một tệp cấu hình XML trong thư mục res/values/ của dự án và đặt tên tệp là wear.xml.
  2. Thêm tài nguyên có tên android_wear_capabilities vào wear.xml.
  3. Xác định tính năng mà thiết bị cung cấp.

Lưu ý: Tính năng là các chuỗi tuỳ chỉnh mà bạn xác định và phải là duy nhất trong ứng dụng của mình.

Ví dụ sau cho biết cách thêm tính năng có tên voice_transcription vào wear.xml:

<resources xmlns:tools="http://schemas.android.com/tools"
           tools:keep="@array/android_wear_capabilities">
    <string-array name="android_wear_capabilities">
        <item>voice_transcription</item>
    </string-array>
</resources>

Truy xuất các nút có tính năng bắt buộc

Ban đầu, bạn có thể phát hiện các nút có khả năng bằng cách gọi phương thức getCapability của lớp CapabilityClient. Để sử dụng phương thức này, ứng dụng Wear OS và ứng dụng dành cho điện thoại của bạn phải có cùng mã nhận dạng ứng dụng. Ví dụ sau cho thấy cách truy xuất kết quả của các nút có thể truy cập theo cách thủ công bằng tính năng voice_transcription:

Kotlin

private const val VOICE_TRANSCRIPTION_CAPABILITY_NAME = "voice_transcription"
...
private fun setupVoiceTranscription() {
    val capabilityInfo: CapabilityInfo = Tasks.await(
            Wearable.getCapabilityClient(context)
                    .getCapability(
                            VOICE_TRANSCRIPTION_CAPABILITY_NAME,
                            CapabilityClient.FILTER_REACHABLE
                    )
    )
    // capabilityInfo has the reachable nodes with the transcription capability
    updateTranscriptionCapability(capabilityInfo)
}

Java

private static final String
    VOICE_TRANSCRIPTION_CAPABILITY_NAME = "voice_transcription";
    ...
private void setupVoiceTranscription() {
    CapabilityInfo capabilityInfo = Tasks.await(
        Wearable.getCapabilityClient(context).getCapability(
            VOICE_TRANSCRIPTION_CAPABILITY_NAME, CapabilityClient.FILTER_REACHABLE));
    // capabilityInfo has the reachable nodes with the transcription capability
    updateTranscriptionCapability(capabilityInfo);
}

Để phát hiện các nút có khả năng kết nối với thiết bị đeo, hãy đăng ký một bản sao của trình nghe, cụ thể là OnCapabilityChangedListener của đối tượng CapabilityClient. Ví dụ sau cho thấy cách đăng ký trình nghe và truy xuất kết quả bằng các nút có thể truy cập có khả năng voice_transcription:

Kotlin

private fun setupVoiceTranscription() {
    updateTranscriptionCapability(capabilityInfo).also { capabilityListener ->
        Wearable.getCapabilityClient(context).addListener(
                capabilityListener,
                VOICE_TRANSCRIPTION_CAPABILITY_NAME
        )
    }
}

Java

private void setupVoiceTranscription() {
    ...
    // This example uses a Java 8 Lambda. You can use named or anonymous classes.
    CapabilityClient.OnCapabilityChangedListener capabilityListener =
        capabilityInfo -> { updateTranscriptionCapability(capabilityInfo); };
    Wearable.getCapabilityClient(context).addListener(
        capabilityListener,
        VOICE_TRANSCRIPTION_CAPABILITY_NAME);
}

Sau khi phát hiện các nút có khả năng, hãy xác định nơi gửi thông báo. Hãy chọn một nút ở gần thiết bị đeo của bạn để giảm thiểu việc định tuyến thông báo qua nhiều nút. Nút lân cận được định nghĩa là một nút giúp kết nối trực tiếp với thiết bị này. Để xác định xem một nút có phải là nút lân cận hay không, chẳng hạn như được kết nối qua Bluetooth, hãy gọi phương thức Node.isNearby(). Nếu có nhiều nút là nút lân cận, hãy chọn một nút tuỳ ý. Tương tự, nếu không có nút nào là nút lân cận, hãy tuỳ ý chọn một nút có khả năng kết nối.

Ví dụ sau cho thấy cách bạn có thể xác định nút phù hợp nhất để sử dụng:

Kotlin

private var transcriptionNodeId: String? = null

private fun updateTranscriptionCapability(capabilityInfo: CapabilityInfo) {
    transcriptionNodeId = pickBestNodeId(capabilityInfo.nodes)
}

private fun pickBestNodeId(nodes: Set<Node>): String? {
    // Find a nearby node or pick one arbitrarily.
    return nodes.firstOrNull { it.isNearby }?.id ?: nodes.firstOrNull()?.id
}

Java

private String transcriptionNodeId = null;

private void updateTranscriptionCapability(CapabilityInfo capabilityInfo) {
    Set<Node> connectedNodes = capabilityInfo.getNodes();

    transcriptionNodeId = pickBestNodeId(connectedNodes);
}

private String pickBestNodeId(Set<Node> nodes) {
    String bestNodeId = null;
    // Find a nearby node or pick one arbitrarily.
    for (Node node : nodes) {
        if (node.isNearby()) {
            return node.getId();
         }
         bestNodeId = node.getId();
    }
    return bestNodeId;
}

Gửi thông báo

Sau khi xác định một nút để sử dụng, hãy gửi thông báo bằng lớp MessageClient.

Ví dụ sau cho thấy cách gửi một thông báo đến nút có khả năng chép lời qua một thiết bị đeo. Lệnh gọi này đồng bộ và chặn các quá trình xử lý cho đến khi hệ thống đưa thông báo vào hàng đợi để phân phối.

Lưu ý: Mã kết quả thành công không đảm bảo việc gửi thông báo. Nếu ứng dụng của bạn yêu cầu độ tin cậy (tính an toàn) của dữ liệu, hãy cân nhắc sử dụng các đối tượng DataItem hoặc lớp ChannelClient để gửi dữ liệu giữa các thiết bị.

Kotlin

const val VOICE_TRANSCRIPTION_MESSAGE_PATH = "/voice_transcription"
...
private fun requestTranscription(voiceData: ByteArray) {
    transcriptionNodeId?.also { nodeId ->
        val sendTask: Task<*> = Wearable.getMessageClient(context).sendMessage(
                nodeId,
                VOICE_TRANSCRIPTION_MESSAGE_PATH,
                voiceData
        ).apply {
            addOnSuccessListener { ... }
            addOnFailureListener { ... }
        }
    }
}

Java

public static final String VOICE_TRANSCRIPTION_MESSAGE_PATH = "/voice_transcription";
private void requestTranscription(byte[] voiceData) {
    if (transcriptionNodeId != null) {
        Task<Integer> sendTask =
            Wearable.getMessageClient(context).sendMessage(
              transcriptionNodeId, VOICE_TRANSCRIPTION_MESSAGE_PATH, voiceData);
         // You can add success and/or failure listeners,
         // Or you can call Tasks.await() and catch ExecutionException
         sendTask.addOnSuccessListener(...);
         sendTask.addOnFailureListener(...);
    } else {
        // Unable to retrieve node with transcription capability
    }
}

Lưu ý: Để tìm hiểu thêm về các lệnh gọi không đồng bộ và đồng bộ đến dịch vụ của Google Play và thời điểm sử dụng từng lệnh, hãy xem phần API Tasks.

Bạn cũng có thể phát thông báo tới toàn bộ nút được kết nối. Để truy xuất toàn bộ nút được kết nối mà bạn có thể gửi thông báo đến, hãy triển khai mã sau:

Kotlin

private fun getNodes(): Collection<String> {
    return Tasks.await(Wearable.getNodeClient(context).connectedNodes).map { it.id }
}

Java

private Collection<String> getNodes() {
    HashSet <String>results = new HashSet<String>();
    List<Node> nodes =
        Tasks.await(Wearable.getNodeClient(context).getConnectedNodes());
    for (Node node : nodes.getNodes()) {
        results.add(node.getId());
    }
    return results;
}

Nhận thông báo

Để nhận thông báo về các thông báo đã nhận, hãy triển khai giao diện MessageClient.OnMessageReceivedListener để cung cấp trình nghe cho các sự kiện thông báo. Sau đó, đăng ký trình nghe bằng phương thức addListener. Ví dụ sau cho thấy cách bạn có thể triển khai trình nghe để kiểm tra VOICE_TRANSCRIPTION_MESSAGE_PATH. Nếu điều kiện này là true, hãy bắt đầu một hoạt động để xử lý dữ liệu thoại.

Kotlin

fun onMessageReceived(messageEvent: MessageEvent) {
    if (messageEvent.path == VOICE_TRANSCRIPTION_MESSAGE_PATH) {
        val startIntent = Intent(this, MainActivity::class.java).apply {
            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            putExtra("VOICE_DATA", messageEvent.data)
        }
        startActivity(this, startIntent)
    }
}

Java

@Override
public void onMessageReceived(MessageEvent messageEvent) {
    if (messageEvent.getPath().equals(VOICE_TRANSCRIPTION_MESSAGE_PATH)) {
        Intent startIntent = new Intent(this, MainActivity.class);
        startIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startIntent.putExtra("VOICE_DATA", messageEvent.getData());
        startActivity(this, startIntent);
    }
}

Mã này yêu cầu thêm chi tiết triển khai. Tìm hiểu về cách triển khai dịch vụ hoặc hoạt động trình nghe hoàn chỉnh trong bài viết Nghe các sự kiện lớp dữ liệu.