Tạo thẻ thông tin đầu tiên trong Wear OS

1. Giới thiệu

Ba thẻ thông tin: thể dục, tin nhắn, lịch.

Thẻ thông tin Wear OS giúp bạn dễ dàng truy cập thông tin và các hành động mà người dùng cần để hoàn thành công việc. Chỉ cần thao tác vuốt từ mặt đồng hồ, người dùng có thể thấy thông tin dự báo mới nhất hoặc khởi động đồng hồ hẹn giờ.

Thẻ thông tin chạy dưới dạng một phần giao diện người dùng hệ thống thay vì chạy trong vùng chứa ứng dụng. Chúng ta sẽ sử dụng Dịch vụ để mô tả bố cục và nội dung của thẻ thông tin. Sau đó, giao diện người dùng hệ thống sẽ hiển thị thẻ thông tin khi cần.

Bạn sẽ thực hiện

656045bed9c45083.png

Bạn sẽ tạo thẻ thông tin cho một ứng dụng nhắn tin để cho thấy các cuộc trò chuyện gần đây. Từ giao diện này, người dùng có thể chuyển sang 3 tác vụ phổ biến sau:

  • Mở một cuộc trò chuyện
  • Soạn một tin nhắn mới

Kiến thức bạn sẽ học được

Trong lớp học lập trình này, bạn sẽ tìm hiểu cách viết Thẻ thông tin dành cho Wear OS của riêng mình, bao gồm cách:

  • Tạo một TileService
  • Thử nghiệm một thẻ thông tin trên thiết bị
  • Xem trước giao diện người dùng của một thẻ thông tin trong Android Studio
  • Phát triển giao diện người dùng của một thẻ thông tin
  • Thêm hình ảnh
  • Xử lý các lượt tương tác

Điều kiện tiên quyết

  • Kiến thức cơ bản về Kotlin

2. Chuẩn bị

Ở bước này, bạn sẽ thiết lập môi trường và tải dự án ban đầu xuống.

Bạn cần có

Trước khi bắt đầu, nếu bạn chưa quen dùng Wear OS, hãy đọc hướng dẫn nhanh hữu ích này. Hướng dẫn trên bao gồm hướng dẫn thiết lập trình mô phỏng Wear OS và mô tả cách sử dụng hệ thống.

Tải mã xuống

Nếu đã cài đặt git, bạn chỉ cần chạy lệnh dưới đây để nhân bản mã từ kho lưu trữ này.

git clone https://github.com/android/codelab-wear-tiles.git
cd codelab-wear-tiles

Nếu không có git, bạn có thể nhấp vào nút sau đây để tải tất cả mã dành cho lớp học lập trình này:

Mở dự án trong Android Studio

Trên cửa sổ "Welcome to Android Studio" (Chào mừng bạn đến với Android Studio), hãy chọn c01826594f360d94.png Open an Existing Project (Mở một Dự án hiện có) hoặc File > Open (Tệp > Mở) rồi chọn thư mục [Download Location].

3. Tạo thẻ thông tin cơ bản

Điểm truy cập của một thẻ thông tin là dịch vụ thẻ thông tin. Ở bước này, bạn sẽ đăng ký dịch vụ và xác định bố cục cho thẻ thông tin.

HelloWorldTileService

Một lớp triển khai TileService cần chỉ định 2 phương thức sau:

  • onTileResourcesRequest(requestParams: ResourcesRequest): ListenableFuture<Resources>
  • onTileRequest(requestParams: TileRequest): ListenableFuture<Tile>

Phương thức đầu tiên trả về một đối tượng Resources giúp liên kết các chuỗi mã nhận dạng với những tài nguyên hình ảnh mà chúng ta sẽ dùng trong thẻ thông tin.

Phương thức thứ hai trả về nội dung mô tả thẻ thông tin bao gồm cả bố cục. Đây là nơi chúng ta xác định bố cục của một thẻ thông tin và cách dữ liệu liên kết với bố cục này.

Mở HelloWorldTileService.kt từ mô-đun start. Tất cả thay đổi mà bạn thực hiện sẽ có mặt ở mô-đun trên. Ngoài ra, chúng tôi còn cung cấp mô-đun finished nếu bạn muốn xem kết quả của lớp học lập trình.

HelloWorldTileService mở rộng SuspendingTileService, một trình bao bọc phù hợp với coroutine Kotlin trong thư viện Thẻ thông tin Horologist. Horologist là một nhóm thư viện của Google dùng để bổ sung các tính năng mà nhà phát triển Wear OS thường yêu cầu nhưng vẫn chưa có trên Jetpack.

SuspendingTileService cung cấp 2 hàm tạm ngưng (là các phiên bản coroutine tương đương của những hàm trong TileService):

  • suspend resourcesRequest(requestParams: ResourcesRequest): Resources
  • suspend tileRequest(requestParams: TileRequest): Tile

Để tìm hiểu thêm về coroutine, hãy xem tài liệu về Coroutine Kotlin trên Android.

HelloWorldTileService vẫn chưa hoàn tất. Chúng tôi cần đăng ký dịch vụ trong tệp kê khai và cũng cần triển khai tileLayout.

Đăng ký dịch vụ thẻ thông tin

Sau khi được đăng ký trong tệp kê khai, dịch vụ thẻ thông tin sẽ xuất hiện trong danh sách các thẻ thông tin hiện có để người dùng thêm.

Hãy thêm <service> bên trong phần tử <application>:

start/src/main/AndroidManifest.xml

<service
    android:name="com.example.wear.tiles.hello.HelloWorldTileService"
    android:icon="@drawable/ic_waving_hand_24"
    android:label="@string/hello_tile_label"
    android:description="@string/hello_tile_description"
    android:exported="true"
    android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER">
    
    <intent-filter>
        <action android:name="androidx.wear.tiles.action.BIND_TILE_PROVIDER" />
    </intent-filter>

    <!-- The tile preview shown when configuring tiles on your phone -->
    <meta-data
        android:name="androidx.wear.tiles.PREVIEW"
        android:resource="@drawable/tile_hello" />
</service>

Biểu tượng và nhãn được dùng (dưới dạng phần giữ chỗ) khi thẻ thông tin tải lần đầu, hoặc nếu xảy ra lỗi khi tải thẻ thông tin. Tiếp đó, siêu dữ liệu ở phía cuối xác định hình ảnh xem trước, được hiển thị trong băng chuyền khi người dùng thêm một thẻ thông tin.

Xác định bố cục cho thẻ thông tin

HelloWorldTileService có một hàm tên là tileLayout, chứa TODO() là phần nội dung. Bây giờ, hãy thay hàm này bằng một phương thức triển khai, nơi chúng ta xác định bố cục cho thẻ thông tin:

start/src/main/java/com/example/wear/tiles/hello/HelloWorldTileService.kt

fun tileLayout(
    context: Context,
    deviceConfiguration: DeviceParametersBuilders.DeviceParameters,
    message: String,
) =
    materialScope(
        context = context,
        deviceConfiguration = deviceConfiguration,
        allowDynamicTheme = false,
    ) {
        primaryLayout(mainSlot = { text(message.layoutString) })
    }

Và đó là Thẻ thông tin đầu tiên trên Wear OS mà bạn tạo ra! Hãy cài đặt và xem giao diện của thẻ thông tin này.

4. Kiểm thử thẻ thông tin trên một thiết bị

Sau khi chọn mô-đun khởi đầu trong trình đơn thả xuống cấu hình chạy, bạn có thể cài đặt ứng dụng (mô-đun start) trên thiết bị hoặc trình mô phỏng và cài đặt thẻ thông tin theo cách thủ công như cách người dùng thao tác.

Tuy nhiên, Android Studio có một lối tắt để thực hiện việc này: bằng cách nhấn vào biểu tượng "run service" (chạy dịch vụ) (▷) trong rãnh, sau đó chọn "Run "HelloWorldTileService"" (Chạy "HelloWorldTileService"). Thao tác này sẽ cài đặt và chạy thẻ thông tin trên một thiết bị đã kết nối.

ded9f9355abd02f3.png

Chọn "Run "HelloWorldTileService"" (Chạy "HelloWorldTileService") để tạo và chạy thẻ thông tin trên một thiết bị đã kết nối. Giao diện sẽ giống như ảnh chụp màn hình dưới đây.

693c130912097be6.png

Biểu tượng "waving hand" (vẫy tay) xuất hiện ở đầu màn hình là do hệ thống cung cấp. Để thay đổi biểu tượng này, hãy sửa đổi thuộc tính android:icon cho phần tử <service> của thẻ thông tin trong tệp kê khai.

Để thuận tiện, quy trình này cũng sẽ tạo một "cấu hình chạy" "HelloWorldTileService" để sử dụng sau này.

b3335148771abbeb.png

5. Thêm hàm xem trước

Chúng ta có thể xem trước giao diện người dùng của thẻ thông tin trong Android Studio. Việc này giúp rút ngắn vòng hồi tiếp khi phát triển giao diện người dùng, từ đó tăng tốc độ phát triển.

Hãy thêm một bản xem trước thẻ thông tin cho HelloWorldTileService vào cuối tệp HelloWorldTileService.kt.

start/src/main/java/com/example/wear/tiles/hello/HelloWorldTileService.kt

@Preview(device = WearDevices.SMALL_ROUND, name = "Small Round")
@Preview(device = WearDevices.LARGE_ROUND, name = "Large Round")
internal fun helloLayoutPreview(context: Context): TilePreviewData {
    return TilePreviewData {
        TilePreviewHelper.singleTimelineEntryTileBuilder(
            helloLayout(context, it.deviceConfiguration, "Hello, preview tile!")
        )
            .build()
    }
}

Hãy sử dụng chế độ chỉnh sửa "Split" (Chia đôi) để xem trước thẻ thông tin:

khung hiển thị chia đôi màn hình của Android Studio với mã xem trước ở bên trái và hình ảnh thẻ thông tin ở bên phải.

Lưu ý không sử dụng chú giải @Composable. Mặc dù Thẻ thông tin và Hàm có khả năng kết hợp dùng cùng một giao diện người dùng xem trước, nhưng Thẻ thông tin không sử dụng Compose và không phải là thành phần kết hợp.

6. Tạo một thẻ thông tin cho ứng dụng nhắn tin

cf18db0f604b1999.png

Thẻ thông tin cho ứng dụng nhắn tin chúng ta sắp tạo có tính đặc trưng của một thẻ thông tin thực tế. Không giống như ví dụ về HelloWorld, ví dụ này minh hoạ các thành phần Material 3 Expressive, hiển thị hình ảnh và xử lý các hoạt động tương tác để mở ứng dụng.

MessagingTileService

MessagingTileService mở rộng lớp SuspendingTileService mà chúng ta đã thấy trước đó.

7. Thêm thành phần giao diện người dùng

Thư viện ProtoLayout cung cấp các bố cục và thành phần tạo sẵn, giúp bạn tạo các thẻ thông tin phù hợp với thiết kế Material 3 Expressive mới nhất cho Wear OS.

Thêm phần phụ thuộc Tiles Material vào tệp build.gradle:

start/build.gradle

implementation "androidx.wear.protolayout:protolayout-material3:$protoLayoutVersion"

Thêm mã bố cục vào hàm tileLayout(), là phần nội dung của hàm materialScope(). Thao tác này sẽ tạo một bố cục bao gồm 2 hàng (mỗi hàng có hai nút) và một nút ở cạnh.

Tìm dòng "TODO() // Add primaryLayout()" rồi thay thế bằng mã bên dưới.

start/src/main/java/com/example/wear/tiles/messaging/tile/Layout.kt

primaryLayout(
    mainSlot = {
        // This layout code assumes "contacts" contains at least 4 elements, for sample code
        // that can handle an arbitrary number of contacts, and also shows different numbers
        // of contacts based on the physical screen size, see
        // <https://github.com/android/wear-os-samples/tree/main/WearTilesKotlin>.
        Column.Builder()
            .apply {
                setWidth(expand())
                setHeight(expand())
                addContent(
                    buttonGroup {
                        buttonGroupItem { contactButton(contacts[0]) }
                        buttonGroupItem { contactButton(contacts[1]) }
                    }
                )
                addContent(DEFAULT_SPACER_BETWEEN_BUTTON_GROUPS)
                addContent(
                    buttonGroup {
                        buttonGroupItem { contactButton(contacts[2]) }
                        buttonGroupItem { contactButton(contacts[3]) }
                    }
                )
            }
            .build()
    },
    bottomSlot = {
        textEdgeButton(
            onClick = clickable(), // TODO: Launch new conversation activity
            labelContent = { text("New".layoutString) },
        )
    },
)

Hàm contactButton() trong cùng một tệp sẽ tạo các nút người liên hệ riêng lẻ. Nếu người liên hệ có hình ảnh được liên kết, hình ảnh đó sẽ xuất hiện trên nút. Nếu không, tên viết tắt của người liên hệ sẽ được dùng.

Tại thời điểm này, bạn có thể nhận thấy mặc dù bố cục chung là chính xác nhưng hình ảnh lại bị thiếu:

809bdb9d1213c376.png

Bạn sẽ thấy điều tương tự nếu triển khai thẻ thông tin cho một thiết bị:

4671bb2eafdcc528.png

Ở bước tiếp theo, chúng ta sẽ thêm những hình ảnh còn thiếu.

8. Thêm hình ảnh

Nhìn chung, Thẻ thông tin bao gồm 2 thành phần: bố cục (tham chiếu tài nguyên theo mã nhận dạng chuỗi) và chính tài nguyên đó (có thể là hình ảnh).

Hiện tại, mã của chúng ta đang cung cấp bố cục, chứ không phải chính tài nguyên đó. Để khắc phục lỗi với bản xem trước, chúng ta cần cung cấp "tài nguyên" hình ảnh. Để làm việc này, hãy tìm "TODO: Add onTileResourceRequest" (Việc cần làm: Thêm onTileResourceRequest) rồi thêm mã bên dưới vào TilePreviewData() ở dạng một đối số bổ sung có tên:

start/src/main/java/com/example/wear/tiles/messaging/tile/Layout.kt

// Additional named argument to TilePreviewData
onTileResourceRequest = { resourcesRequest ->
    Resources.Builder()
        .setVersion(resourcesRequest.version)
        .apply {
            contacts.forEach {
                if (it.avatarSource is AvatarSource.Resource) {
                    addIdToImageMapping(
                        it.imageResourceId(),
                        it.avatarSource.resourceId
                    )
                }
            }
        }
        .build()
}

Giờ đây, các hình ảnh sẽ xuất hiện trong bản xem trước:

e77d746268f293f2.png

Tuy nhiên, nếu triển khai thẻ thông tin cho một thiết bị, hình ảnh sẽ bị thiếu. Để khắc phục vấn đề này, hãy thay thế hàm resourcesRequest() trong Service.kt bằng đoạn mã sau:

start/src/main/java/com/example/wear/tiles/messaging/tile/Service.kt

override suspend fun resourcesRequest(
    requestParams: ResourcesRequest
): Resources {
    // resourceIds is a list of the ids we need to provide images for. If we're passed an empty
    // list, set resourceIds to all resources.
    val resourceIds =
        requestParams.resourceIds.ifEmpty {
            contacts.map { it.imageResourceId() }
        }

    // resourceMap maps (tile) resource ids to (Android) resource ids.
    val resourceMap =
        contacts
            .mapNotNull {
                when (it.avatarSource) {
                    is AvatarSource.Resource ->
                        it.imageResourceId() to
                            it.avatarSource.resourceId
                    else -> null
                }
            }
            .toMap()
            .filterKeys {
                it in resourceIds
            } // filter to only the resources we need

    // Add images in the resourceMap to the Resources object, and return the result.
    return Resources.Builder()
        .setVersion(requestParams.version)
        .apply {
            resourceMap.forEach { (id, imageResource) ->
                addIdToImageMapping(id, imageResource)
            }
        }
        .build()
}

Giờ đây, hình ảnh cũng được hiển thị khi triển khai thẻ thông tin cho một thiết bị:

cf18db0f604b1999.png

Ở bước tiếp theo, chúng ta sẽ xử lý các lượt nhấp vào từng thành phần.

9. Xử lý các lượt tương tác

Một trong những điều hữu ích nhất mà thẻ thông tin mang lại là cung cấp lối tắt đến hành trình trọng yếu của người dùng. Khác với trình chạy ứng dụng chỉ mở ứng dụng, ở đây chúng ta có không gian để cung cấp các lối tắt theo ngữ cảnh vào một màn hình cụ thể trong ứng dụng.

Cho đến nay, chúng ta đã sử dụng một hành động giả do clickable() không có đối số cung cấp cho khối và mỗi nút. Bạn có thể làm điều này cho các bản xem trước không có tính tương tác, nhưng hãy tìm hiểu cách thêm thao tác cho các thành phần.

LaunchAction

Bạn có thể dùng LaunchAction để chạy một hoạt động. Hãy sửa đổi Layout sao cho khi nhấn vào nút "New" (Mới), hành trình "cuộc trò chuyện mới" của người dùng sẽ bắt đầu.

Tìm dòng "TODO: Launch new conversation activity" (Việc cần làm: Chạy hoạt động trò chuyện mới) và thay thế clickable() bằng:

start/src/main/java/com/example/wear/tiles/messaging/tile/Layout.kt

clickable(
    id = "new_button",
    action =
        launchAction(
            ComponentName(
                "com.example.wear.tiles",
                "com.example.wear.tiles.messaging.MainActivity",
            ),
            mapOf(
                MainActivity.EXTRA_JOURNEY to
                    ActionBuilders.stringExtra(
                        MainActivity.EXTRA_JOURNEY_NEW
                    )
            ),
        ),
)

Triển khai lại thẻ thông tin. Giờ đây, thay vì không làm gì cả, thao tác nhấn vào "New" (Mới) sẽ khởi chạy MainActivity và bắt đầu hành trình "cuộc trò chuyện mới" của người dùng:

a08c28b4a142fb8f.png

Tương tự, hãy sửa đổi Layout để thao tác nhấn vào nút liên hệ sẽ bắt đầu một cuộc trò chuyện với một người dùng cụ thể.

Tìm dòng "Launch open conversation activity" (Khởi chạy hoạt động cuộc trò chuyện đang mở) và thay thế clickable() bằng:

start/src/main/java/com/example/wear/tiles/messaging/tile/Layout.kt

clickable(
    id = contact.id.toString(),
    action =
        launchAction(
            ComponentName(
                "com.example.wear.tiles",
                "com.example.wear.tiles.messaging.MainActivity",
            ),
            mapOf(
                MainActivity.EXTRA_JOURNEY to
                    ActionBuilders.stringExtra(
                        MainActivity
                            .EXTRA_JOURNEY_CONVERSATION
                    ),
                MainActivity.EXTRA_CONVERSATION_CONTACT to
                    ActionBuilders.stringExtra(
                        contact.name
                    ),
            ),
        ),
)

Triển khai lại thẻ thông tin. Giờ đây, thay vì không làm gì cả, bạn có thể bắt đầu cuộc trò chuyện với một người liên hệ bằng cách nhấn vào người đó:

b684a1ced0b226f9.png

10. Xin chúc mừng

Xin chúc mừng! Bạn đã tìm hiểu cách tạo thẻ thông tin dành cho Wear OS!

Tiếp theo là gì?

Để biết thêm thông tin, hãy xem các phương pháp triển khai Thẻ thông tin Golden trên GitHub, hướng dẫn về Thẻ thông tin trong Wear OSnguyên tắc thiết kế.