Tiết lộ dữ liệu cho các chức năng mặt đồng hồ trên Wear OS

1. Tiết lộ dữ liệu của bạn cho các Chức năng

Lớp học lập trình này sẽ hướng dẫn bạn cách tạo nguồn dữ liệu chức năng.

Ý tưởng và thiết lập

Sau khi kết thúc lớp học lập trình, bạn sẽ biết cách cung cấp dữ liệu cho các chức năng mặt đồng hồ trên Wear OS.

Khái niệm

Chức năng (complication) là một tính năng của mặt đồng hồ ngoài giờ và phút. Ví dụ: mặt đồng hồ trên hình ảnh dưới đây có bốn chức năng.

39f4ebe8dc4800b0.png

API Chức năng dành cho cả ứng dụng mặt đồng hồ và ứng dụng nguồn dữ liệu:

  • Nguồn dữ liệu chức năng cung cấp dữ liệu, chẳng hạn như mức pin, thời tiết, số bước, v.v.
  • Nhà phát triển mặt đồng hồ có thể hiển thị dữ liệu đó trong một chức năng trên mặt đồng hồ của họ
  • Người dùng chọn nguồn dữ liệu họ muốn cho các chức năng của mình

Screen Shot 2016-05-17 at 5.14.50 PM.png

Trong lớp học lập trình này, chúng tôi đề cập đến việc tạo nguồn dữ liệu chức năng. Nếu bạn cũng muốn thêm các chức năng vào mặt đồng hồ, hãy xem mẫu mặt đồng hồ.

Hãy bắt đầu!

Nhân bản kho lưu trữ dự án ban đầu

Để giúp bạn nhanh chóng bắt đầu, chúng tôi đã chuẩn bị một dự án để bạn dựa vào đó mà xây dựng ứng dụng. Dự án này chứa một số mã cơ bản và các tuỳ chọn cài đặt ứng dụng cần thiết cho lớp học lập trình này.

Nếu bạn đã cài đặt Git, hãy chạy lệnh dưới đây. (Bạn có thể kiểm tra xem Git đã cài đặt chưa bằng cách nhập git --version vào Terminal/dòng lệnh và xác minh lệnh đó thực thi đúng cách):

 git clone https://github.com/googlecodelabs/complications-data-source.git

Nếu không có Git, bạn có thể tải dự án xuống dưới dạng tệp zip:

Nhập dự án

Khởi động Android Studio rồi chọn "Open an existing Android Studio project" (Mở dự án Android Studio hiện có) từ màn hình Chào mừng. Mở thư mục dự án và nhấp đúp vào tệp build.gradle trong thư mục complications-data-source.

Ở góc trên bên trái cửa sổ dự án, nếu đang ở chế độ xem Android, bạn sẽ thấy một tập hợp các biểu tượng thư mục tương tự các biểu tượng trong ảnh chụp màn hình bên dưới. (Nếu bạn đang ở chế độ xem Project (Dự án), hãy mở rộng dự án complications-data-source để xem tập hợp các biểu tượng trong thư mục.)

786caabc75caee70.png

Có hai biểu tượng thư mục. Cả hai đều đại diện cho một mô-đun. Hãy lưu ý Android Studio có thể mất vài giây để biên dịch dự án ở chế độ nền trong lần đầu tiên. Trong khoảng thời gian này, bạn sẽ thấy một vòng quay trong thanh trạng thái ở phía dưới Android Studio:

27f04b5598a2f95e.png

Chờ cho đến khi các quy trình kết thúc trước khi thực hiện thay đổi mã, để cho phép Android Studio lấy tất cả các thành phần cần thiết.

Tìm hiểu về dự án ban đầu

Bạn đã thiết lập và sẵn sàng bắt đầu tiết lộ dữ liệu cho các chức năng. Chúng ta sẽ bắt đầu từ mô-đun base. Bạn phải thêm mã từ mỗi bước vào base.

Bạn có thể sử dụng mô-đun complete trong lớp học lập trình làm điểm tham chiếu để kiểm tra công việc của mình (hoặc làm tham chiếu nếu gặp vấn đề).

Tổng quan về các thành phần khoá cho nguồn dữ liệu

  • ComplicationTapBroadcastReceiver – Lớp được dùng để cập nhật dữ liệu về chức năng thông qua PendingIntent.
  • CustomComplicationDataSourceService – Lớp được dùng để tiết lộ dữ liệu của chúng ta cho các chức năng. Tệp được đặt trong thư mục base/java/com/example/android/wearable/complicationsdatasource. Trong Android Studio, tính năng này nằm trong base/java/com.example.android.wearable.complicationsdatasource. Ở lớp học này, chúng ta sẽ chủ yếu xử lý theo 4 phương pháp:
  • onComplicationActivated – Được gọi khi một chức năng được kích hoạt cùng dữ liệu của bạn.
  • getPreviewData – Xem trước dữ liệu cho chức năng được sử dụng trong giao diện người dùng trình chỉnh sửa (thường chỉ là nội dung tĩnh).
  • onComplicationRequest – Phần lớn hoạt động của chúng ta đều được thực hiện theo phương thức này. Phương thức này được gọi bất kỳ khi nào một chức năng đang hoạt động cần cập nhật dữ liệu từ nguồn.
  • onComplicationDeactivated – Được gọi khi chức năng đã được kích hoạt.

Thiết lập trình mô phỏng

Nếu bạn cần trợ giúp thiết lập trình mô phỏng Wear OS, vui lòng tham khảo phần "Launch the emulator and run your Wear app" (Chạy trình mô phỏng và chạy ứng dụng Wear) trên trang "Tạo và chạy ứng dụng cho thiết bị đeo".

Chạy dự án khởi động

Hãy chạy ứng dụng trên đồng hồ.

  • Kết nối thiết bị Wear OS hoặc khởi động trình mô phỏng.
  • Trên thanh công cụ, hãy chọn cấu hình "base" (cơ sở) từ bộ chọn thả xuống và nhấp vào nút hình tam giác xanh lục (Run (Chạy)) bên cạnh:

a04699aa4cf2ca12.png

  • Nếu gặp lỗi như lỗi bên dưới (Lỗi khi khởi chạy hoạt động), hãy thay đổi khởi chạy mặc địnhActivity (hướng dẫn bên dưới). 6ea74bcba8278349.png

Ngược lại, nếu được nhắc Activity sử dụng khi khởi chạy ứng dụng, hãy chọn "Do not launch Activity" (Không chạy Hoạt động).

  • Để thay đổi khởi chạy mặc định Activity (nếu cần, từ bước trước đó), nhấp vào bộ chọn thả xuống ở bên trái mũi tên xanh lục và nhấp vào "edit configurations" (chỉnh sửa cấu hình).

1e3e1dc73655ccd8.png

Chọn "base" (cơ sở) và bạn sẽ thấy một cửa sổ tương tự như cửa sổ bên dưới. Chọn "Nothing" (Không có gì) trong phần Launch Options (Tuỳ chọn khởi chạy) và nhấp vào Run (Chạy). Sau này khi muốn thử phát hành mô-đun khác, bạn cũng phải thao tác như vậy.

5e98572969d8228.png

  • Chọn thiết bị Android hoặc trình mô phỏng rồi nhấp vào OK. Thao tác này sẽ cài đặt dịch vụ trên thiết bị Wear OS hoặc trình mô phỏng.
  • Sau vài giây, dịch vụ của bạn đã được xây dựng và sẵn sàng để triển khai. Bạn sẽ thấy một vòng quay trên thanh trạng thái ở cuối Android Studio.
  • Nếu thẻ này chưa có trên thẻ "Build" (Tạo) ở dưới cùng bên trái Android Studio, hãy chọn thẻ đó để bạn có thể xem tiến trình cài đặt. Khi kết thúc quá trình cài đặt, bạn sẽ thấy thông báo "Build: completed successfully" (Tạo: hoàn tất thành công).

5ea92276833c0446.png

  • Hãy chọn mặt đồng hồ cho phép bạn chọn một chức năng. Trong trường hợp này, chúng ta đã chọn Elements Digital (Phần tử số) nhưng phần tử này có thể không có trên đồng hồ của bạn.

a5cf2c605206efe2.png

Lưu ý vì đây là lần đầu chạy mặt đồng hồ này, bạn sẽ cần chọn mặt đồng hồ đó trong mục "Add more watch faces" (Thêm mặt đồng hồ khác). Sau khi được chọn, mặt đồng hồ này sẽ xuất hiện trong danh sách mặt đồng hồ để bạn chọn.

  • Giờ đây, mặt đồng hồ đã chọn sẽ ở chính giữa trình đơn Favorite (Mục yêu thích) (xem hình ảnh bên dưới). Nhấp vào biểu tượng bánh răng ở dưới cùng.

f17fb6b4cfe06182.png

  • Đối với mặt đồng hồ này, bạn nên chọn Data (Dữ liệu). Đối với mặt đồng hồ tuỳ chỉnh mà bạn đang sử dụng, giao diện người dùng có thể khác đi.

aef4fca32751a15a.png

  • Chọn bất kỳ vị trí nào, tức là bất kỳ "+" (chức năng) nào.

461f8a704fbc6496.png

  • Cuối cùng, cuộn xuống rồi chọn dịch vụ Complications Data Source Codelab (Lớp học lập trình về nguồn dữ liệu chức năng). (Sau khi chọn, bạn phải vuốt sang trái vài lần hoặc đặt cả bàn tay lên thiết bị để thoát.)

b4d0d14140ce0120.png

  • Ở đầu ra, bạn sẽ thấy cả thông báo nhật ký "onComplicationActivated()" và "onComplicationRequest ()" (mặc dù sẽ không có thông báo nào hiển thị ở vị trí chức năng).
  • Nếu bạn không thấy thông báo nhật ký, hãy thử triển khai lại mặt đồng hồ bằng cách nhấn nút tam giác xanh lục trên thanh công cụ.
  • Nếu bạn chưa hiểu rõ cách xem dữ liệu Log, nhấp vào thẻ ở cuối Android Studio có nhãn "6: Logcat". Đặt trình đơn thả xuống thành tên thiết bị/trình mô phỏng và gói com.example.android.wearable.complicationsdatasource (bên dưới là ảnh chụp màn hình).

af9cf164f9c598fc.png

"Nhưng chờ đã! Không có gì hiển thị trong vùng dữ liệu đã chọn!" Đừng lo, chúng tôi chưa cung cấp bất kỳ dữ liệu nào. Chúng tôi sẽ bổ sung thông tin này trong bước tiếp theo.

Trên một số đồng hồ, Mặt đồng hồ phần tử có các chức năng đã bật, do đó bạn có thể thấy chức năng đã điền sẵn hiển thị trên đồng hồ. Ngoài ra, đừng lo lắng nếu trình mô phỏng của bạn có đám mây bị gạch ngang thay vì biểu tượng máy bay. Chúng ta không cần kết nối với điện thoại hoặc Internet cho ứng dụng của lớp học lập trình này.

52da39817e329e7a.png

Tóm tắt

Trong bước này, bạn đã tìm hiểu về:

  • Wear OS và các khái niệm đằng sau việc tiết lộ dữ liệu cho các chức năng
  • Kiến thức cơ bản về điểm xuất phát của chúng tôi (mô-đun cơ sở)
  • Triển khai và chạy mặt đồng hồ

Tiếp theo

Hãy bắt đầu tiết lộ một vài dữ liệu.

2. Tiết lộ dữ liệu văn bản ngắn

Bước mã 2

Trong bước này, chúng ta sẽ bắt đầu tiết lộ dữ liệu. Các chức năng chấp nhận một số loại dữ liệu. Ở bước này, chúng ta sẽ trả về loại dữ liệu Văn bản ngắn.

Nếu bạn thấy khó hiểu về các khái niệm được thảo luận tại đây, vui lòng tham khảo mô-đun complete và xem các bước này có thể được triển khai như thế nào.

Chỉ định loại dữ liệu mà nguồn của bạn hỗ trợ

Mở lại tệp AndroidManifest.xml và xem dịch vụ CustomComplicationDataSourceService. Lưu ý đến bộ lọc ý định:

<action android:name=
    "android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST"/>

Điều này cho hệ thống biết rằng dịch vụ của bạn mở rộng ComplicationDataSourceService hoặc SuspendingComplicationDataSourceService (biến thể hỗ trợ Kotlin Coroutine) và có thể gửi dữ liệu cho các chức năng.

Tiếp theo là phần tử meta-data chỉ định(các) loại dữ liệu mà chúng ta hỗ trợ. Trong trường hợp này, chúng ta hỗ trợ SMALL_IMAGE, nhưng đối với bước này, hãy thay đổi tuỳ chọn đó thành SHORT_TEXT. Hãy thay đổi thành phần meta-data đầu tiên của bạn thành các thành phần sau:

<meta-data
    android:name="android.support.wearable.complications.SUPPORTED_TYPES"
    android:value="SHORT_TEXT"/>

Tiết lộ dữ liệu của bạn

Như đã nêu ở trên, onComplicationActivated() được gọi khi nguồn dữ liệu được kích hoạt. Đây là vị trí/thời gian thích hợp để thực hiện các thiết lập cơ bản cần được thực hiện một lần mỗi khi kích hoạt. Chúng ta sẽ không thực hiện thao tác đó ở lớp học lập trình này vì mẫu của chúng ta tương đối đơn giản.

Lệnh gọi onComplicationRequest() là khi các yêu cầu chức năng hoạt động cập nhật dữ liệu.

Phương thức onComplicationRequest() được kích hoạt vì nhiều lý do:

  • Chức năng hoạt động trên mặt đồng hồ được thay đổi để sử dụng nguồn này
  • Chức năng sử dụng nguồn này sẽ hoạt động trở lại
  • Bạn đã kích hoạt bản cập nhật từ lớp của chính mình qua ComplicationDataSourceUpdateRequester.requestUpdate() hoặc ComplicationDataSourceUpdateRequester.requestUpdateAll() .
  • Khoảng thời gian bạn đã chỉ định trong tệp kê khai đã trôi qua

Mở CustomComplicationDataSourceService .kt và di chuyển con trỏ xuống phương thức onComplicationRequest(). Xoá dòng "return null", sau đó sao chép và dán mã bên dưới trong lệnh gọi Log.d() ban đầu:

// Retrieves your data, in this case, we grab an incrementing number from Datastore.
val number: Int = applicationContext.dataStore.data
    .map { preferences ->
        preferences[TAP_COUNTER_PREF_KEY] ?: 0
    }
    .first()

val numberText = String.format(Locale.getDefault(), "%d!", number)

Trong trường hợp này, chúng ta sẽ truy xuất một int được lưu trữ từ DataStore đại diện cho dữ liệu của chúng ta. Đây dễ trở thành một lệnh gọi đến cơ sở dữ liệu của bạn.

Để tương tác với DataStore, bạn phải sử dụng coroutine để thu thập Flow mà nó tạo ra. Bạn có thể nhận thấy onComplicationRequest() là một hàm suspend, vì vậy chúng ta có thể thu thập dữ liệu thông qua Flow mà không kích hoạt cụ thể một coroutine.

Sau khi truy xuất giá trị số nguyên, chúng ta sẽ chuyển đổi nó thành chuỗi đơn giản để chuẩn bị chuyển đổi nó sang đối tượng ComplicationData, tức là loại dữ liệu mà chức năng (compilation) có thể hiểu được.

Tiếp theo, sao chép và dán mã bên dưới mã bạn vừa thêm..

return when (request.complicationType) {

    ComplicationType.SHORT_TEXT -> ShortTextComplicationData.Builder(
        text = PlainComplicationText.Builder(text = numberText).build(),
        contentDescription = PlainComplicationText
            .Builder(text = "Short Text version of Number.").build()
    )
        .build()

    else -> {
        if (Log.isLoggable(TAG, Log.WARN)) {
            Log.w(TAG, "Unexpected complication type ${request.complicationType}")
        }
        null
    }
}

Trong mã này, chúng ta trả về một đối tượng ComplicationData dựa trên loại chức năng, tức là chúng ta sẽ trả về một ShortTextComplicationData (một lớp con của ComplicationData) cho loại dữ liệu SHORT_TEXT.

Một loại dữ liệu nhất định có thể bao gồm nhiều trường. Ví dụ: SHORT_TEXT có thể chỉ là đoạn văn bản hoặc tiêu đề và văn bản, hoặc hình ảnh và văn bản đơn sắc (tất cả phải bao gồm nội dung mô tả để cho biết khả năng tiếp cận).

Ở đây, chúng ta chỉ đặt trường bắt buộc và không đặt các trường không bắt buộc. Để tìm hiểu thêm về các loại và trường này, xem tài liệu của chúng ta.

Bạn có thể hỏi lý do chúng ta sử dụng câu lệnh thời gian để tạo dữ liệu. Sau này, chúng ta sẽ hỗ trợ nhiều dạng dữ liệu dựa trên loại dữ liệu mà hệ thống yêu cầu. Bằng cách sử dụng câu lệnh thời gian, chúng ta có thể dễ dàng thêm các loại dữ liệu mới (LONG_TEXT, RANGED_VALUE, v.v.) sau này.

Cuối cùng, chúng ta sẽ trả về giá trị rỗng nếu không hỗ trợ loại dữ liệu này.

Phương pháp cuối cùng của bạn sẽ có dạng như sau:

override suspend fun onComplicationRequest(request: ComplicationRequest): ComplicationData? {
    Log.d(TAG, "onComplicationRequest() id: ${request.complicationInstanceId}")

    // Retrieves your data, in this case, we grab an incrementing number from Datastore.
    val number: Int = applicationContext.dataStore.data
        .map { preferences ->
            preferences[TAP_COUNTER_PREF_KEY] ?: 0
        }
        .first()

    val numberText = String.format(Locale.getDefault(), "%d!", number)

    return when (request.complicationType) {

        ComplicationType.SHORT_TEXT -> ShortTextComplicationData.Builder(
            text = PlainComplicationText.Builder(text = numberText).build(),
            contentDescription = PlainComplicationText
                .Builder(text = "Short Text version of Number.").build()
        )
            .build()

        else -> {
            if (Log.isLoggable(TAG, Log.WARN)) {
                Log.w(TAG, "Unexpected complication type ${request.complicationType}")
            }
            null
        }
    }
}

Chạy lại ứng dụng

Trong bước đầu tiên, bạn đã tìm hiểu cách cài đặt dịch vụ dữ liệu chức năng trên thiết bị hoặc trình mô phỏng của mình. Bây giờ, hãy làm lại điều đó! Cài đặt ứng dụng rồi chọn lại chức năng (compilation), tức là vuốt mặt đồng hồ, chọn bánh răng, chuyển đến cùng chức năng và chọn Lớp học lập trình về Nguồn dữ liệu cho chức năng. Bạn sẽ thấy như sau:

caae484f1f2508fd.png

Tóm tắt

Trong bước này, bạn đã tìm hiểu về:

  • Cách chỉ định loại dữ liệu mà nguồn của bạn có thể hỗ trợ
  • Dữ liệu của bạn nên được yêu cầu ở tần suất như thế nào khi một chức năng hoạt động đang sử dụng dữ liệu đó
  • Nơi hiển thị dữ liệu của bạn trên Wear OS

Tiếp theo

Hãy thử hỗ trợ một loại dữ liệu khác.

3. Kích hoạt bản cập nhật dữ liệu chức năng

Bước mã 3

Ở bước này, chúng ta sẽ kích hoạt các bản cập nhật trong dữ liệu khi người dùng nhấn vào chức năng của chúng ta.

Nếu bạn thấy khó hiểu về các khái niệm được thảo luận tại đây, vui lòng tham khảo mô-đun complete và xem các bước này có thể được triển khai như thế nào.

Chỉ định tần suất chức năng (complication) nên làm mới dữ liệu

Mở tệp AndroidManifest.xml và xem lại dịch vụ CustomComplicationDataSourceService.

Hãy lưu ý trường UPDATE_PERIOD_SECONDS trong phần tử meta-data. Thông tin này cho biết tần suất bạn muốn hệ thống kiểm tra các bản cập nhật dữ liệu khi nguồn dữ liệu của bạn đang hoạt động.

Hiện tại, nó được đặt thành 600 giây (10 phút). Vì muốn cập nhật chức năng của mình để phản hồi một hành động của người dùng nên chúng ta sẽ cập nhật thường xuyên hơn. Mặc dù có thể giảm thời gian này nhưng hệ thống có thể không kích hoạt bản cập nhật trong khoảng thời gian ngắn hơn vài phút.

Cách hiệu quả hơn là "kiểu đẩy" trong đó chúng ta yêu cầu hệ thống cập nhật chính xác khi dữ liệu thay đổi.

Thay đổi tần suất cập nhật từ 600 thành 0, điều này có nghĩa là chúng ta sẽ trực tiếp ping hệ thống khi dữ liệu thay đổi thay vì dựa vào cập nhật định kỳ. Lưu ý đối với siêu dữ liệu, đây là yêu cầu bắt buộc.

<meta-data
    android:name="android.support.wearable.complications.UPDATE_PERIOD_SECONDS"
    android:value="0"/>

Thông báo cho hệ thống về dữ liệu chức năng mới có sẵn

Mở ComplicationTapBroadcastReceiver.kt. Lớp BroadcastReceiver này sẽ cập nhật dữ liệu về chức năng của chúng ta khi nó được kích hoạt. (Đừng quên chúng ta chỉ lưu dữ liệu vào DataStore.)

Lớp này cũng cung cấp phương thức trợ giúp để tạo PendingIntent (kích hoạt nó dưới dạng BroadcastReceiver).

Hiện tại, phương thức onReceive(), trích xuất nguồn dữ liệu và mã (id) chức năng (compilation) từ ý định, đồng thời cập nhật số nguyên trong DataStore. Chúng ta cần cho chức năng biết dữ liệu đã được cập nhật.

Di chuyển xuống cuối phương thức onReceive(). Sau khối cuối cùng, bạn sẽ thấy nhận xét "Request an update for the..." (Yêu cầu cập nhật cho...) Sao chép và dán mã bên dưới nhận xét đó.

// Request an update for the complication that has just been tapped, that is,
// the system call onComplicationUpdate on the specified complication data
// source.
val complicationDataSourceUpdateRequester =
    ComplicationDataSourceUpdateRequester.create(
        context = context,
        complicationDataSourceComponent = dataSource
    )
complicationDataSourceUpdateRequester.requestUpdate(complicationId)

Thao tác này giúp Wear OS biết dữ liệu của chức năng đã được cập nhật. Chúng ta cần ba phần dữ liệu để làm việc này:

  • context (ngữ cảnh) - Context có sẵn dưới dạng một đối số cho phương thức này: onReceive().
  • complicationDataSourceComponentDataSource của chức năng được chuyển vào như Extra từ PendingIntent để kích hoạt BroadcastReceiver này.
  • complicationId: Số nguyên độc nhất được mặt đồng hồ gán cho vị trí hiển thị chức năng. int được chuyển vào dưới dạng Extra từ PendingIntent sẽ kích hoạt BroadcastReceiver này.

Chúng ta đã hoàn tất bước này và phương pháp cuối cùng của bạn sẽ có dạng như sau:

override fun onReceive(context: Context, intent: Intent) {

    // Retrieve complication values from Intent's extras.
    val extras = intent.extras ?: return
    val dataSource = extras.getParcelable<ComponentName>(EXTRA_DATA_SOURCE_COMPONENT) ?: return
    val complicationId = extras.getInt(EXTRA_COMPLICATION_ID)

    // Required when using async code in onReceive().
    val result = goAsync()

    // Launches coroutine to update the DataStore counter value.
    scope.launch {
        try {
            context.dataStore.edit { preferences ->
                val currentValue = preferences[TAP_COUNTER_PREF_KEY] ?: 0

                // Update data for complication.
                val newValue = (currentValue + 1) % MAX_NUMBER

                preferences[TAP_COUNTER_PREF_KEY] = newValue
            }

            // Request an update for the complication that has just been tapped, that is,
            // the system call onComplicationUpdate on the specified complication data
            // source.
            val complicationDataSourceUpdateRequester =
                ComplicationDataSourceUpdateRequester.create(
                    context = context,
                    complicationDataSourceComponent = dataSource
                )
            complicationDataSourceUpdateRequester.requestUpdate(complicationId)
        } finally {
            // Always call finish, even if cancelled
            result.finish()
        }
    }
}

Thêm một thao tác nhấn vào chức năng

BroadcastReceiver không chỉ cập nhật dữ liệu mà còn thông báo cho hệ thống rằng dữ liệu mới có sẵn (xem bước trước). Cần thêm một hành động nhấn vào chức năng để kích hoạt BroadcastReceiver.

Mở CustomComplicationDataSourceService.kt và chuyển xuống phương thức onComplicationRequest().

Bên dưới câu lệnh Log.d() đầu tiên và ở trên vị trí số nguyên được truy xuất từ DataStore, sao chép/dán mã bên dưới:

// Create Tap Action so that the user can trigger an update by tapping the complication.
val thisDataSource = ComponentName(this, javaClass)
// We pass the complication id, so we can only update the specific complication tapped.
val complicationPendingIntent =
    ComplicationTapBroadcastReceiver.getToggleIntent(
        this,
        thisDataSource,
        request.complicationInstanceId
    )

Ở bước trước, chúng ta đã biết cần cả hai phần dữ liệu này để BroadcastReceiver hoạt động (nguồn dữ liệu và mã chức năng). Chúng ta chuyển cả hai thông tin này dưới dạng thông số bổ sung cho PendingIntent.

Tiếp theo, chúng ta phải chỉ định PendingIntent cho sự kiện nhấn của chức năng này.

Tìm câu lệnh thời gian cho ST và thêm dòng này lên trên lệnh gọi .build().

    .setTapAction(complicationPendingIntent)

Khối mã bây giờ sẽ giống như thế này.

ComplicationType.SHORT_TEXT -> ShortTextComplicationData.Builder(
    text = PlainComplicationText.Builder(text = numberText).build(),
    contentDescription = PlainComplicationText
        .Builder(text = "Short Text version of Number.").build()
)
    .setTapAction(complicationPendingIntent)
    .build()

Thao tác này chỉ thêm một dòng, phương thức .setTapAction() để chỉ định PendingIntent mới cho thao tác nhấn cho chức năng đó.

Chúng ta đã thực hiện xong bước này. Phương pháp cuối cùng của bạn sẽ có dạng như sau:

override suspend fun onComplicationRequest(request: ComplicationRequest): ComplicationData? {
    Log.d(TAG, "onComplicationRequest() id: ${request.complicationInstanceId}")

    // Create Tap Action so that the user can trigger an update by tapping the complication.
    val thisDataSource = ComponentName(this, javaClass)
    // We pass the complication id, so we can only update the specific complication tapped.
    val complicationPendingIntent =
        ComplicationTapBroadcastReceiver.getToggleIntent(
            this,
            thisDataSource,
            request.complicationInstanceId
        )

    // Retrieves your data, in this case, we grab an incrementing number from Datastore.
    val number: Int = applicationContext.dataStore.data
        .map { preferences ->
            preferences[TAP_COUNTER_PREF_KEY] ?: 0
        }
        .first()

    val numberText = String.format(Locale.getDefault(), "%d!", number)

    return when (request.complicationType) {

        ComplicationType.SHORT_TEXT -> ShortTextComplicationData.Builder(
            text = PlainComplicationText.Builder(text = numberText).build(),
            contentDescription = PlainComplicationText
                .Builder(text = "Short Text version of Number.").build()
        )
            .setTapAction(complicationPendingIntent)
            .build()

        else -> {
            if (Log.isLoggable(TAG, Log.WARN)) {
                Log.w(TAG, "Unexpected complication type ${request.complicationType}")
            }
            null
        }
    }
}

Chạy lại ứng dụng

Cài đặt ứng dụng rồi chọn lại chức năng (compilation), tức là vuốt mặt đồng hồ, chọn bánh răng, chuyển đến cùng chức năng và chọn nguồn Complications Data Source Codelab (Lớp học lập trình về Nguồn dữ liệu cho chức năng). Bạn sẽ thấy nội dung như đã thấy trước đây. Tuy nhiên, giờ bạn có thể nhấn vào chức năng này và dữ liệu sẽ được cập nhật.

a9d767e37161e609.png

Tóm tắt

Trong bước này, bạn đã tìm hiểu về:

  • Cách thông báo cho hệ thống biết dữ liệu chức năng của bạn đã được cập nhật
  • Cách liên kết một PendingIntent vào một hành động nhấn trong chức năng

Tiếp theo

Hãy thử hỗ trợ một loại dữ liệu khác.

4. Tiết lộ dữ liệu văn bản dài

Bước mã 4

Khi tiết lộ dữ liệu của mình cho các chức năng, bạn nên hỗ trợ nhiều loại dữ liệu hơn và xem các loại dữ liệu trông như thế nào trong các chức năng.

Chỉ định một loại dữ liệu được hỗ trợ khác

Mở lại tệp AndroidManifest.xml và xem khai báo về dịch vụ CustomComplicationDataSourceService.

Thay đổi phần tử meta-data SUPPORTED_TYPES từ SHORT_TEXT thành LONG_TEXT. Thay đổi của bạn sẽ giống như sau:

<meta-data
    android:name="android.support.wearable.complications.SUPPORTED_TYPES"
    android:value="LONG_TEXT"/>

Thêm hỗ trợ cho LONG TEXT

Mở CustomComplicationDataSourceService.kt, di chuyển xuống câu lệnh when trong phương thức onComplicationRequest() và thêm mã sau bên dưới phần cuối của trường hợp TYPE_SHORT_TEXT và phía trên trường hợp mặc định.

ComplicationType.LONG_TEXT -> LongTextComplicationData.Builder(
    text = PlainComplicationText.Builder(text = "Number: $numberText").build(),
    contentDescription = PlainComplicationText
        .Builder(text = "Long Text version of Number.").build()
)
    .setTapAction(complicationPendingIntent)
    .build()

Câu lệnh when sẽ giống như sau:

return when (request.complicationType) {

    ComplicationType.SHORT_TEXT -> ShortTextComplicationData.Builder(
        text = PlainComplicationText.Builder(text = numberText).build(),
        contentDescription = PlainComplicationText
            .Builder(text = "Short Text version of Number.").build()
    )
        .setTapAction(complicationPendingIntent)
        .build()

    ComplicationType.LONG_TEXT -> LongTextComplicationData.Builder(
        text = PlainComplicationText.Builder(text = "Number: $numberText").build(),
        contentDescription = PlainComplicationText
            .Builder(text = "Long Text version of Number.").build()
    )
        .setTapAction(complicationPendingIntent)
        .build()

    else -> {
        if (Log.isLoggable(TAG, Log.WARN)) {
            Log.w(TAG, "Unexpected complication type ${request.complicationType}")
        }
        null
    }
}

Bạn hẳn đã thấy chúng ta chỉ đóng gói lại dữ liệu đó trong một định dạng mới. Hãy xem giao diện của nó.

Cách kiểm tra tiến trình và gỡ lỗi

Cài đặt dịch vụ của bạn, nhưng lần này hãy chọn chức năng vùng dưới cùng trước khi chọn nguồn dịch vụ chức năng của bạn:

518b646d3c3f3305.png

Bạn sẽ thấy một hình ảnh như hình bên dưới. Lưu ý mỗi chức năng được lưu trữ trong một khoá riêng, vì vậy bạn có thể thấy các giá trị khác nhau nếu đã đặt chức năng ở nhiều vị trí:

17ec0506f1412676.png

Tóm tắt

Trong bước này, bạn đã tìm hiểu về:

  • Thay đổi và hỗ trợ các loại dữ liệu chức năng khác nhau

Tiếp theo

Chúng ta muốn hỗ trợ thêm một loại dữ liệu trước khi gộp tất cả lại.

5. Tiết lộ dữ liệu văn bản trong phạm vi

Bước mã 5

Mặc dù có thể tiết lộ dữ liệu của mình nhưng chúng ta hãy tiếp tục tìm hiểu cách hỗ trợ thêm nhiều loại dữ liệu.

Chỉ định một loại dữ liệu được hỗ trợ khác

Mở lại tệp AndroidManifest.xml và xem dịch vụ CustomComplicationDataSourceService.

Thay đổi phần tử meta-data SUPPORTED_TYPES thành RANGED_VALUE. Thay đổi của bạn sẽ có dạng như sau:

<meta-data
    android:name="android.support.wearable.complications.SUPPORTED_TYPES"
    android:value="RANGED_VALUE"/>

Thêm tuỳ chọn hỗ trợ cho RANGED VALUES

Giá trị theo phạm vi không chỉ hiển thị văn bản mà còn hiển thị cả hình ảnh cho biết khoảng cách giữa giá trị tối thiểu và giá trị tối đa của bạn. Loại chức năng này cho biết mức pin còn lại trên thiết bị hoặc số bước còn lại để đáp ứng mục tiêu của bạn.

1fe1943a5ad29076.png

Mở CustomComplicationDataSourceService .kt, di chuyển con trỏ xuống câu lệnh when trong phương thức onComplicationRequest() và thêm mã này trong trường hợp TYPE_LONG_TEXT và phía trên trường hợp mặc định:

ComplicationType.RANGED_VALUE -> RangedValueComplicationData.Builder(
    value = number.toFloat(),
    min = 0f,
    max = ComplicationTapBroadcastReceiver.MAX_NUMBER.toFloat(),
    contentDescription = PlainComplicationText
        .Builder(text = "Ranged Value version of Number.").build()
)
    .setText(PlainComplicationText.Builder(text = numberText).build())
    .setTapAction(complicationPendingIntent)
    .build()

Câu lệnh thời gian nên có dạng như sau:

return when (request.complicationType) {

    ComplicationType.SHORT_TEXT -> ShortTextComplicationData.Builder(
        text = PlainComplicationText.Builder(text = numberText).build(),
        contentDescription = PlainComplicationText
            .Builder(text = "Short Text version of Number.").build()
    )
        .setTapAction(complicationPendingIntent)
        .build()

    ComplicationType.LONG_TEXT -> LongTextComplicationData.Builder(
        text = PlainComplicationText.Builder(text = "Number: $numberText").build(),
        contentDescription = PlainComplicationText
            .Builder(text = "Long Text version of Number.").build()
    )
        .setTapAction(complicationPendingIntent)
        .build()

    ComplicationType.RANGED_VALUE -> RangedValueComplicationData.Builder(
        value = number.toFloat(),
        min = 0f,
        max = ComplicationTapBroadcastReceiver.MAX_NUMBER.toFloat(),
        contentDescription = PlainComplicationText
            .Builder(text = "Ranged Value version of Number.").build()
    )
        .setText(PlainComplicationText.Builder(text = numberText).build())
        .setTapAction(complicationPendingIntent)
        .build()

    else -> {
        if (Log.isLoggable(TAG, Log.WARN)) {
            Log.w(TAG, "Unexpected complication type ${request.complicationType}")
        }
        null
    }
}

Vui lòng lưu ý một lần nữa, chúng tôi chỉ gói lại dữ liệu đó trong một định dạng mới. Hãy xem giao diện của nó.

Cách kiểm tra tiến trình và gỡ lỗi

Cài đặt dịch vụ và chọn một vị trí khác.

461f8a704fbc6496.png

Bây giờ bạn sẽ thấy như sau:

ffa6ea8f2ed3eb2a.png

Bạn có thể thấy một vòng tròn hướng tâm bao quanh số làm nổi bật số tương đương 3/20.

Tóm tắt

Trong bước này, bạn đã tìm hiểu về:

  • Thay đổi và hỗ trợ các loại dữ liệu chức năng khác nhau

Tiếp theo

Chúng ta kết thúc lớp học lập trình này bằng việc bật tất cả các biến thể của loại dữ liệu.

6. Tiết lộ cả 3 loại dữ liệu

Bước mã 6

Hiện tại, nguồn dữ liệu chức năng của chúng ta hỗ trợ ba biến thể dữ liệu (RANGED_VALUE, SHORT_TEXT,LONG_TEXT).

Trong bước cuối cùng này, chúng ta sẽ cho hệ thống chúng ta hỗ trợ biết cả 3 biến thể này.

Chỉ định nhiều loại dữ liệu được hỗ trợ

Mở lại tệp AndroidManifest.xml và xem dịch vụ CustomComplicationDataSourceService.

Thay đổi phần tử meta-data SUPPORTED_TYPES thành RANGED_VALUE,SHORT_TEXT,LONG_TEXT. Thay đổi của bạn bây giờ sẽ có dạng như sau:

<meta-data
    android:name="android.support.wearable.complications.SUPPORTED_TYPES"
    android:value="RANGED_VALUE,SHORT_TEXT,LONG_TEXT"/>

Kiểm tra tiến trình

Cài đặt dịch vụ của bạn.

b3a7c0c8063c2f60.png

Trong trường hợp này, mặt đồng hồ ưu tiên loại dữ liệu theo phạm vi hơn là loại dữ liệu ngắn và dài. Tuy nhiên, nếu chức năng này chỉ hỗ trợ loại văn bản ngắn thì dữ liệu vẫn sẽ hiển thị vì mặt đồng hồ hỗ trợ cả 3 loại dữ liệu. Lưu ý bản thân mặt đồng hồ sẽ chỉ định loại dữ liệu mà chức năng hỗ trợ và thứ tự ưu tiên của các loại đó.

Tóm tắt

Trong bước này, bạn đã tìm hiểu về:

  • Hỗ trợ nhiều loại dữ liệu chức năng

7. Bạn đã hoàn tất! Tiếp theo là gì?

Bạn có thể hỗ trợ nhiều loại dữ liệu khác trong các chức năng (bao gồm hình ảnh nhỏ, hình ảnh lớn và biểu tượng). Thử mở rộng lớp học lập trình này bằng cách tự triển khai một số loại đó.

Để biết thêm thông tin về cách phát triển các chức năng cho mặt đồng hồ và tạo nguồn dữ liệu cho chức năng, truy cập vào Watch Face Complications (Chức năng trên mặt đồng hồ)

Để biết thêm thông tin chi tiết về cách phát triển mặt đồng hồ Wear OS, truy cập vào https://developer.android.com/training/wearables/watch-faces/index.html