Xử lý các sự kiện Lớp dữ liệu trên Wear

Stay organized with collections Save and categorize content based on your preferences.

Khi thực hiện lệnh gọi đến API Lớp dữ diệu, bạn có thể nhận được trạng thái của lệnh gọi khi hoàn tất. Bạn cũng có thể theo dõi các sự kiện dữ liệu do những thay đổi về dữ liệu mà ứng dụng của bạn thực hiện ở bất cứ đâu trên mạng Wear OS by Google.

Hãy tham khảo các tài nguyên liên quan sau:

Chờ trạng thái của lệnh gọi Lớp dữ liệu

Các lệnh gọi đến API Lớp dữ liệu (ví dụ: một lệnh gọi sử dụng phương thức putDataItem của lớp DataClient) đôi khi trả về một đối tượng Task<ResultType>. Ngay sau khi đối tượng Task được tạo, hoạt động sẽ được đưa vào hàng đợi trong nền. Nếu bạn không thực hiện thao tác nào thêm sau đó thì hoạt động cuối cùng sẽ tự hoàn tất. Tuy nhiên, thông thường, bạn sẽ muốn thực hiện một thao tác nào đó với kết quả sau hoạt động hoàn tất, vì vậy, đối tượng Task cho phép bạn đợi trạng thái kết quả một cách đồng bộ hoặc không đồng bộ.

Lệnh gọi không đồng bộ

Nếu mã đang chạy trên luồng giao diện người dùng chính thì bạn đừng thực hiện việc chặn lệnh gọi đến API Lớp dữ liệu. Bạn có thể chạy các lệnh gọi không đồng bộ bằng cách thêm phương thức gọi lại vào đối tượng Task. Phương thức này sẽ kích hoạt khi thao tác này hoàn tất:

Kotlin

// Using Kotlin function references
task.addOnSuccessListener(::handleDataItem)
task.addOnFailureListener(::handleDataItemError)
task.addOnCompleteListener(::handleTaskComplete)
...
fun handleDataItem(dataItem: DataItem) { ... }
fun handleDataItemError(exception: Exception) { ... }
fun handleTaskComplete(task: Task<DataItem>) { ... }

Java

// Using Java 8 Lambdas.
task.addOnSuccessListener(dataItem -> handleDataItem(dataItem));
task.addOnFailureListener(exception -> handleDataItemError(exception));
task.addOnCompleteListener(task -> handleTaskComplete(task));

Hãy xem API Tasks (API nhiệm vụ) để biết các khả năng khác, bao gồm cả khả năng liên kết việc thực thi các nhiệm vụ khác nhau với nhau.

Lệnh gọi đồng bộ

Nếu mã của bạn đang chạy trên một luồng xử lý riêng biệt trong dịch vụ nền (trường hợp này là trong WearableListenerService), thì việc chặn các lệnh gọi là điều hoàn toàn phù hợp. Trong trường hợp này, bạn có thể gọi Tasks.await() trên đối tượng Task. Thao tác này sẽ chặn cho đến khi yêu cầu hoàn tất và trả về đối tượng Result:

Kotlin

try {
    Tasks.await(dataItemTask).apply {
        Log.d(TAG, "Data item set: $uri")
    }
}
catch (e: ExecutionException) { ... }
catch (e: InterruptedException) { ... }

Java

try {
    DataItem item = Tasks.await(dataItemTask);
    Log.d(TAG, "Data item set: " + item.getUri());
} catch (ExecutionException | InterruptedException e) {
  ...
}

Theo dõi các sự kiện Lớp dữ liệu

Vì lớp dữ liệu đồng bộ hoá và gửi dữ liệu trên thiết bị cầm tay và thiết bị đeo, nên thường việc theo dõi các sự kiện quan trọng là cần thiết. Ví dụ về các sự kiện như vậy bao gồm việc tạo các mục dữ liệu và nhận thông báo.

Để theo dõi các sự kiện lớp dữ liệu, bạn có hai tuỳ chọn:

Với cả hai tuỳ chọn này, bạn sẽ ghi đè các phương thức gọi lại sự kiện dữ liệu cho các sự kiện mà bạn muốn xử lý.

Lưu ý: Về mức sử dụng pin, WearableListenerService được đăng ký trong tệp kê khai của ứng dụng và có thể chạy ứng dụng nếu ứng dụng chưa chạy. Nếu bạn chỉ cần theo dõi các sự kiện khi ứng dụng đang chạy, trường hợp này thường xảy ra với các ứng dụng tương tác, thì bạn không nên sử dụng WearableListenerService. Thay vào đó, hãy đăng ký trình nghe trực tiếp, chẳng hạn như phương thức addListener của lớp DataClient. Điều này có thể làm giảm tải trên hệ thống và giảm mức sử dụng pin.

Bằng một WearableListenerService

Bạn thường tạo các thực thể của dịch vụ này trong cả ứng dụng trên thiết bị đeo và thiết bị cầm tay. Nếu không quan tâm đến các sự kiện dữ liệu đối với một trong những ứng dụng này, thì bạn không cần triển khai dịch vụ này trong ứng dụng cụ thể đó.

Ví dụ: bạn có thể có một ứng dụng cầm tay thiết lập và nhận các đối tượng mục dữ liệu, và một ứng dụng cho thiết bị đeo theo dõi các bản cập nhật này để cập nhật giao diện người dùng. Thiết bị đeo không bao giờ cập nhật mục dữ liệu nào, vì vậy, ứng dụng cầm tay sẽ không theo dõi bất kỳ sự kiện dữ liệu nào từ ứng dụng dành cho thiết bị đeo.

Sau đây là một số sự kiện mà bạn có thể theo dõi bằng cách sử dụng WearableListenerService:

  • onDataChanged(): Mỗi khi một đối tượng mục dữ liệu được tạo, xoá hoặc thay đổi, hệ thống sẽ kích hoạt lệnh gọi lại này trên tất cả các nút được kết nối.
  • onMessageReceived(): Một thông báo gửi từ một nút sẽ kích hoạt lệnh gọi lại này trên nút mục tiêu.
  • onCapabilityChanged(): Khi một thực thể của ứng dụng cho biết một chức năng có sẵn trên mạng, thì sự kiện đó sẽ kích hoạt lệnh gọi lại này. Nếu đang tìm một nút gần đó, bạn có thể truy vấn phương thức isNearby() của các nút được cung cấp trong lệnh gọi lại.

Ngoài những sự kiện trong danh sách này, bạn có thể theo dõi các sự kiện từ ChannelClient.ChannelCallback, chẳng hạn như onChannelOpened().

Tất cả các sự kiện trước đó được thực thi trong một luồng trong nền chứ không phải trên luồng chính.

Để tạo WearableListenerService, hãy làm theo các bước sau:

  1. Tạo một lớp mở rộng WearableListenerService.
  2. Theo dõi những sự kiện mà bạn quan tâm, chẳng hạn như onDataChanged().
  3. Khai báo bộ lọc ý định trong tệp kê khai Android để thông báo cho hệ thống về WearableListenerService. Khai báo này cho phép hệ thống liên kết dịch vụ của bạn nếu cần.

Ví dụ sau đây trình bày cách triển khai một WearableListenerService đơn giản:

Kotlin

private const val TAG = "DataLayerSample"
private const val START_ACTIVITY_PATH = "/start-activity"
private const val DATA_ITEM_RECEIVED_PATH = "/data-item-received"

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

Java

public class DataLayerListenerService extends WearableListenerService {
    private static final String TAG = "DataLayerSample";
    private static final String START_ACTIVITY_PATH = "/start-activity";
    private static final String DATA_ITEM_RECEIVED_PATH = "/data-item-received";

    @Override
    public void onDataChanged(DataEventBuffer dataEvents) {
        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.
        for (DataEvent event : dataEvents) {
            Uri uri = event.getDataItem().getUri();

            // Get the node id from the host value of the URI
            String nodeId = uri.getHost();
            // Set the data of the message to be the bytes of the URI
            byte[] payload = uri.toString().getBytes();

            // Send the RPC
            Wearable.getMessageClient(this).sendMessage(
                  nodeId,  DATA_ITEM_RECEIVED_PATH, payload);
        }
    }
}

Phần tiếp theo giải thích cách sử dụng bộ lọc ý định bằng trình nghe này.

Sử dụng bộ lọc bằng WearableListenerService

Bộ lọc ý định cho ví dụ về WearableListenerService được hiển thị trong phần trước có thể có dạng như sau:

<service android:name=".DataLayerListenerService">
  <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>

Trong bộ lọc này, hành động DATA_CHANGED sẽ thay thế hành động BIND_LISTENER được đề xuất trước đó để chỉ những sự kiện cụ thể mới có thể đánh thức hoặc chạy ứng dụng của bạn. Thay đổi này cải thiện hiệu suất của hệ thống và giảm mức tiêu thụ pin cũng như mức hao tổn khác liên quan đến ứng dụng. Trong ví dụ này, đồng hồ sẽ theo dõi mục dữ liệu /start-activity, còn điện thoại sẽ theo dõi phản hồi tin nhắn /data-item-received.

Áp dụng quy tắc đối sánh bộ lọc tiêu chuẩn của Android Bạn có thể chỉ định nhiều dịch vụ cho mỗi tệp kê khai, nhiều bộ lọc ý định cho mỗi dịch vụ, nhiều hành động cho mỗi bộ lọc và nhiều khổ dữ liệu cho mỗi bộ lọc. Các bộ lọc có thể so khớp trên một máy chủ có chứng nhận ký tự đại diện hoặc trên một máy chủ cụ thể. Để so khớp trên máy chủ có chứng nhận ký tự đại diện, hãy sử dụng host="*". Để so khớp trên một máy chủ cụ thể, hãy chỉ định host=<node_id>.

Bạn cũng có thể so khớp một đường dẫn giá trị cố định hoặc tiền tố đường dẫn. Nếu so khớp theo đường dẫn hoặc tiền tố đường dẫn, bạn phải chỉ định một ký tự đại diện hoặc máy chủ cụ thể. Nếu không làm như vậy, hệ thống sẽ bỏ qua đường dẫn mà bạn đã chỉ định.

Để biết thêm thông tin về các loại bộ lọc mà Wear OS hỗ trợ, hãy xem tài liệu tham khảo về API cho WearableListenerService.

Để biết thêm thông tin về bộ lọc dữ liệu và các quy tắc so khớp, hãy xem tài liệu tham khảo API cho phần tử tệp kê khai data.

Khi so khớp các bộ lọc ý định, bạn cần nhớ hai quy tắc quan trọng sau:

  • Nếu một lược đồ không được chỉ định cho bộ lọc ý định, hệ thống sẽ bỏ qua mọi thuộc tính URI khác.
  • Nếu không có máy chủ nào được chỉ định cho bộ lọc, hệ thống sẽ bỏ qua mọi thuộc tính đường dẫn.

Bằng một trình nghe trực tiếp

Nếu ứng dụng chỉ quan tâm đến các sự kiện lớp dữ liệu khi người dùng đang tương tác với ứng dụng, thì có thể ứng dụng không cần dịch vụ chạy trong thời gian dài để xử lý mọi thay đổi về dữ liệu. Trong trường hợp như vậy, bạn có thể theo dõi các sự kiện trong một hoạt động bằng cách triển khai một hoặc nhiều giao diện sau:

Cách tạo một hoạt động theo dõi các sự kiện dữ liệu:

  1. Triển khai các giao diện mà bạn muốn.
  2. Trong phương thức onCreate() hoặc onResume(), hãy gọi Wearable.getDataClient(this).addListener(), MessageClient.addListener(), CapabilityClient.addListener() hoặc ChannelClient.registerChannelCallback() để thông báo cho các dịch vụ Google Play về việc hoạt động của bạn muốn theo dõi các sự kiện lớp dữ liệu.
  3. Trong onStop() hoặc onPause(), hãy huỷ đăng ký bất kỳ trình nghe nào bằng DataClient.removeListener(), MessageClient.removeListener(), CapabilityClient.removeListener() hoặc ChannelClient.unregisterChannelCallback().
  4. Nếu một hoạt động chỉ quan tâm đến các sự kiện có tiền tố đường dẫn cụ thể, thì bạn có thể thêm trình nghe có bộ lọc tiền tố phù hợp để chỉ nhận dữ liệu liên quan đến trạng thái ứng dụng hiện tại.
  5. Triển khai onDataChanged(), onMessageReceived(), onCapabilityChanged() hoặc phương thức từ ChannelClient.ChannelCallback tuỳ thuộc vào giao diện mà bạn đã triển khai. Các phương thức này được gọi trên luồng chính hoặc bạn có thể chỉ định Looper tuỳ chỉnh bằng cách sử dụng WearableOptions.

Dưới đây là ví dụ triển khai DataClient.OnDataChangedListener:

Kotlin

class MainActivity : Activity(), DataClient.OnDataChangedListener {

    public override fun onResume() {
        Wearable.getDataClient(this).addListener(this)
    }

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

Java

public class MainActivity extends Activity implements DataClient.OnDataChangedListener {

    @Override
    public void onResume() {
        Wearable.getDataClient(this).addListener(this);
    }

    @Override
    protected void onPause() {
        Wearable.getDataClient(this).removeListener(this);
    }

    @Override
    public void onDataChanged(DataEventBuffer dataEvents) {
        for (DataEvent event : dataEvents) {
            if (event.getType() == DataEvent.TYPE_DELETED) {
                Log.d(TAG, "DataItem deleted: " + event.getDataItem().getUri());
            } else if (event.getType() == DataEvent.TYPE_CHANGED) {
                Log.d(TAG, "DataItem changed: " + event.getDataItem().getUri());
            }
        }
    }
}

Sử dụng các bộ lọc với trình nghe trực tiếp

Như đã lưu ý trước đó trên trang này, giống như bạn có thể chỉ định bộ lọc ý định cho các đối tượng WearableListenerService dựa trên tệp kê khai, bạn có thể sử dụng bộ lọc ý định khi đăng ký trình nghe trực tiếp thông qua API của thiết bị đeo. Các quy tắc tương tự có thể áp dụng cho cả trình nghe trực tiếp dựa trên API và trình nghe dựa trên tệp kê khai.

Một mẫu phổ biến là đăng ký trình nghe bằng một đường dẫn hoặc tiền tố đường dẫn cụ thể trong phương thức onResume() của hoạt động, đồng thời xoá trình nghe trong phương thức onPause() của hoạt động. Việc triển khai trình nghe theo cách này cho phép ứng dụng của bạn tiếp nhận các sự kiện có chọn lọc hơn, cải thiện thiết kế và hiệu quả của ứng dụng.