Khi thực hiện lệnh gọi đến Data Layer API (API Lớp dữ liệ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.
Để biết ví dụ về cách làm việc hiệu quả với Data Layer API (API Lớp dữ liệu), hãy xem ứng dụng Mẫu DataLayer của Android.
Chờ trạng thái của lệnh gọi Lớp dữ liệu
Các lệnh gọi đến Data Layer API (API Lớp dữ liệu), chẳng hạn như lệnh gọi sử dụng phương thức putDataItem
của lớp
DataClient
, đôi khi trả về đối tượng
Task<ResultType>
. Ngay sau khi đối tượng Task
được tạo, thao tác này sẽ được đưa vào hàng đợi trong chế độ nền. Nếu bạn không làm gì thêm sau đó thì thao tác này cuối cùng sẽ tự hoàn tất.
Tuy nhiên, thông thường, bạn sẽ muốn làm gì đó với kết quả sau khi thao tác 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 không đồng bộ hoặc đồ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 gửi lệnh gọi chặn đến Data Layer API (API Lớp dữ liệu). Hãy chạy các lệnh gọi không đồng bộ bằng cách thêm phương pháp gọi lại vào đối tượng Task
. Phương pháp này sẽ kích hoạt khi thao tác 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 Task API (API Nhiệm vụ) để biết các khả năng khác, bao gồm cả việc liên kết hoạt động thực thi nhiều nhiệm vụ.
Lệnh gọi đồng bộ
Nếu mã của bạn đang chạy trên một luồng riêng biệt của trình xử lý trong dịch vụ nền, chẳng hạn như trong
WearableListenerService
, thì bạn có thể chặn các lệnh gọi. Trong trường hợp này, bạn có thể gọi Tasks.await()
trên đối tượng Task
để chặn cho đến khi yêu cầu hoàn tất và trả về đối tượng Result
. Lệnh này được minh hoạ trong ví dụ sau:
Lưu ý: Nhớ đừng gọi lệnh này khi đang ở trên luồng chính.
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
Lớp dữ liệu sẽ đồng bộ hoá và gửi dữ liệu giữa các thiết bị cầm tay và thiết bị đeo. Vậy nên, thông thường, bạn cần theo dõi các sự kiện quan trọng như mục dữ liệu đang tạo và thông báo đang nhận.
Để theo dõi các sự kiện lớp dữ liệu, bạn có 2 lựa chọn:
- Tạo một dịch vụ mở rộng
WearableListenerService
. - Tạo một hoạt động hoặc lớp triển khai giao diện
DataClient.OnDataChangedListener
.
Với cả hai lựa chọn này, bạn sẽ ghi đè các phương pháp 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 ý: Hãy cân nhắc mức sử dụng pin của ứng dụng khi chọn phương thức triển khai cho trình nghe. 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 (thường là 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.
Ví dụ: sử dụng phương thức addListener
của lớp DataClient
. Việc này có thể giảm bớt tải trên hệ thống và giảm mức sử dụng pin.
Sử dụng WearableListenerService
Bạn thường tạo các thực thể của WearableListenerService
trong cả ứng dụng cho thiết bị đeo và thiết bị cầm tay. Tuy nhiên, nếu không quan tâm đến các sự kiện dữ liệu ở một trong những ứng dụng nêu trên, thì bạn không cần triển khai dịch vụ trong ứng dụng đó.
Ví dụ: bạn có thể dùng một ứng dụng cho thiết bị cầm tay để đặt và lấy các đối tượng mục dữ liệu, một ứng dụng cho thiết bị đeo giúp theo dõi các bản cập nhật này để cập nhật giao diện người dùng. Ứng dụng cho thiết bị đeo tuyệt đối không cập nhật mục dữ liệu. Vì vậy, ứng dụng cho thiết bị cầm tay sẽ không theo dõi bất kỳ sự kiện dữ liệu nào từ ứng dụng 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, bị 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ừ nút sẽ kích hoạt lệnh gọi lại này trên nút đích.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ứcisNearby()
của các nút được cung cấp trong lệnh gọi lại.
Bạn cũng có thể theo dõi các sự kiện từ
ChannelClient.ChannelCallback
, chẳng hạn như onChannelOpened()
.
Mọi sự kiện trước đó được thực thi trong một luồng ở chế độ 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:
- Tạo một lớp mở rộng
WearableListenerService
. - Theo dõi những sự kiện mà bạn quan tâm, chẳng hạn như
onDataChanged()
. - Khai báo bộ lọc ý định trong tệp kê khai Android để thông báo cho hệ thống về
WearableListenerService
. Thông tin khai báo này giú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 sau đây 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" 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>
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. Để làm việc này, bạn phải chỉ định một ký tự đại diện hoặc bộ lưu trữ cụ thể. Nếu không, 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 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, hãy nhớ 2 quy tắc quan trọng:
- Nếu không có lược đồ nào đượ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ó bộ lưu trữ nào được chỉ định cho bộ lọc, hệ thống sẽ bỏ qua mọi thuộc tính đường dẫn.
Sử dụng 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:
DataClient.OnDataChangedListener
MessageClient.OnMessageReceivedListener
CapabilityClient.OnCapabilityChangedListener
ChannelClient.ChannelCallback
Để tạo một hoạt động giúp theo dõi các sự kiện dữ liệu, hãy làm như sau:
- Triển khai các giao diện mà bạn muốn.
- Trong phương thức
onCreate()
hoặconResume()
, hãy gọiWearable.getDataClient(this).addListener()
,MessageClient.addListener()
,CapabilityClient.addListener()
hoặcChannelClient.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. - Trong
onStop()
hoặconPause()
, hãy huỷ đăng ký bất kỳ trình nghe nào bằngDataClient.removeListener()
,MessageClient.removeListener()
,CapabilityClient.removeListener()
hoặcChannelClient.unregisterChannelCallback()
. - 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.
- 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ỉ địnhLooper
tuỳ chỉnh bằng cách sử dụngWearableOptions
.
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ư đã đề cập trước đó, giống như việc 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 cho thiết bị đeo. Các quy tắc tương tự á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, sau đó xoá trình nghe trong phương thức onPause()
của hoạt động.
Khi triển khai trình nghe theo cách này, ứng dụng của bạn có thể nhận các sự kiện một cách chọn lọc hơn, góp phần cải thiện thiết kế và tính hiệu quả của ứng dụng.