Hiện nội dung cập nhật động trong thẻ thông tin

Kể từ Thẻ thông tin 1.2, bạn có thể truyền trực tuyến nội dung cập nhật dữ liệu nền tảng bằng cách sử dụng biểu thức động. Sau đó, bạn có thể liên kết các nội dung cập nhật này với ảnh động trong thẻ thông tin của mình. Ứng dụng của bạn sẽ nhận được nội dung cập nhật cho giá trị này mỗi giây.

Khi sử dụng biểu thức động, bạn không cần làm mới toàn bộ thẻ thông tin khi nội dung của thẻ thay đổi. Để đem lại trải nghiệm hấp dẫn hơn trong các thẻ thông tin của bạn, hãy tạo ảnh động cho các đối tượng động đó.

Liên kết biểu thức động với nguồn dữ liệu

Không gian tên androidx.wear.protolayoutandroidx.wear.protolayout.material chứa nhiều lớp có các trường chấp nhận biểu thức động. Sau đây là một số ví dụ:

Để dùng biểu thức động làm giá trị có thể có cho một phần tử trong thẻ thông tin của bạn, hãy sử dụng loại thuộc tính động *Prop tương ứng của phần tử đó và chuyển nguồn dữ liệu vào phương thức setDynamicValue() của lớp trình tạo của loại thuộc tính động.

Thẻ thông tin hỗ trợ các loại thuộc tính động sau đây:

Khi dùng một biểu thức động ảnh hưởng đến kích thước thực (bất kỳ giá trị nào trong thẻ thông tin ngoại trừ giá trị màu), bạn còn phải chỉ định một tập hợp các điều kiện ràng buộc có liên quan, chẳng hạn như định dạng chuỗi. Những điều kiện ràng buộc này cho phép trình kết xuất hệ thống xác định khoảng không gian tối đa mà một giá trị có thể chiếm trong thẻ thông tin của bạn. Thông thường, bạn chỉ định các điều kiện ràng buộc này ở cấp phần tử, chứ không phải ở cấp biểu thức động, bằng cách gọi một phương thức bắt đầu bằng setLayoutConstraintsForDynamic*.

Đoạn mã sau đây chỉ ra cách hiện nội dung cập nhật nhịp tim bằng 3 chữ số, với giá trị dự phòng là --:

Kotlin

import androidx.wear.protolayout.material.Text

public override fun onTileRequest(requestParams: RequestBuilders.TileRequest) =
    Futures.immediateFuture(Tile.Builder()
        .setResourcesVersion(RESOURCES_VERSION)
        .setFreshnessIntervalMillis(60 * 60 * 1000) // 60 minutes
        .setTileTimeline(Timeline.fromLayoutElement(
            Text.Builder(this,
                TypeBuilders.StringProp.Builder("--")
                    .setDynamicValue(PlatformHealthSources.heartRateBpm()
                        .format()
                        .concat(DynamicBuilders.DynamicString.constant(" bpm")))
                    .build(),
                StringLayoutConstraint.Builder("000")
                    .build()
                ).build()
            )
        ).build()
    )

Java

import androidx.wear.protolayout.material.Text;

@Override
protected ListenableFuture<Tile> onTileRequest(
       @NonNull TileRequest requestParams
) {
    return Futures.immediateFuture(new Tile.Builder()
        .setResourcesVersion(RESOURCES_VERSION)
        .setFreshnessIntervalMillis(60 * 60 * 1000) // 60 minutes
        .setTileTimeline(Timeline.fromLayoutElement(
            new Text.Builder(
                this,
                new TypeBuilders.StringProp.Builder("--")
                    .setDynamicValue(PlatformHealthSources.heartRateBpm()
                        .format()
                        .concat(DynamicBuilders.DynamicString.constant(" bpm")))
                    .build(),
                new StringLayoutConstraint.Builder("000")
                    .build()
                ).build())
        ).build()
    );
}

Dùng ít biểu thức trong một thẻ thông tin

Wear OS đặt ra giới hạn cho số lượng biểu thức mà một thẻ thông tin có thể có. Nếu một thẻ thông tin có tổng cộng quá nhiều biểu thức động, thì các giá trị động sẽ bị bỏ qua và hệ thống sẽ chuyển về các giá trị tĩnh mà bạn cung cấp cho các loại thuộc tính động tương ứng.

Bạn có thể yên tâm thêm tập hợp biểu thức sau đây vào một thẻ thông tin vì tổng cộng không có quá nhiều biểu thức. Do đó, thẻ thông tin sẽ hoạt động chính xác:

Kotlin

val personHealthInfo = DynamicString.constant("This person has walked ")
    .concat(PlatformHealthSources.dailySteps()
        .div(1000)
        .format())
    .concat("thousands of steps and has a current heart rate ")
    .concat(PlatformHealthSources.heartRateBpm()
        .format())
    .concat(" beats per minute")

Java

DynamicString personHealthInfo =
    DynamicString.constant("This person has walked ")
        .concat(PlatformHealthSources.dailySteps()
            .div(1000)
            .format())
        .concat("thousands of steps and has a current heart rate ")
        .concat(PlatformHealthSources.heartRateBpm()
            .format())
        .concat(" beats per minute");

Tuy nhiên, thẻ thông tin sau có thể có quá nhiều biểu thức:

Kotlin

// Note that this template is applied as many times as the loop iterates.
// The system doesn't reuse dynamic expressions.
val dynamicStringTemplate = PlatformHealthSources.dailySteps()
    .div(1000)
    .format()

for (person in people) {
  // SomeProperty
    .setDynamicValue(
        DynamicBuilders.DynamicString.constant("Steps for ")
            .concat(person)
            .concat(" are ")
            .concat(dynamicStringTemplate)
    )
}

Java

// Note that this template is applied as many times as the loop iterates.
// The system doesn't reuse dynamic expressions.
DynamicString dynamicStringTemplate =
    PlatformHealthSources.dailySteps()
        .div(1000)
        .format();

for (int i = 0; i < people.size(); i++) {
  // SomeProperty
    .setDynamicValue(
        DynamicBuilders.DynamicString.constant("Steps for ")
            .concat(people[i])
            .concat(" are ")
            .concat(dynamicStringTemplate)
    );
}

Hợp nhất dữ liệu động thành một đối tượng trạng thái

Bạn có thể hợp nhất tập hợp nội dung cập nhật mới nhất từ nguồn dữ liệu thành đối tượng trạng thái mà bạn sẽ chuyển vào thẻ thông tin của mình để hiển thị giá trị.

Để dùng thông tin trạng thái trong thẻ thông tin của bạn, hãy hoàn tất các bước sau:

  1. Thiết lập một tập hợp khoá đại diện cho các giá trị khác nhau của trạng thái thẻ thông tin. Sau đây là ví dụ về cách tạo khoá cho lượng nước uống và ghi chú:

    Kotlin

    companion object {
        val KEY_WATER_INTAKE = AppDataKey<DynamicInt32>("water_intake")
        val KEY_NOTE = AppDataKey<DynamicString>("note")
    }
    

    Java

    private static final AppDataKey<DynamicInt32> KEY_WATER_INTAKE =
        new AppDataKey<DynamicInt32>("water_intake");
    private static final AppDataKey<DynamicString> KEY_NOTE =
        new AppDataKey<DynamicString>("note");
    
  2. Trong quá trình triển khai onTileRequest(), hãy gọi setState() và thiết lập mối liên kết ban đầu từ mỗi khoá đến một giá trị dữ liệu động cụ thể:

    Kotlin

    override fun onTileRequest(requestParams: TileRequest):
            ListenableFuture<Tile> {
        val state = State.Builder()
            .addKeyToValueMapping(KEY_WATER_INTAKE,
                DynamicDataBuilders.DynamicDataValue.fromInt(200))
            .addKeyToValueMapping(KEY_NOTE,
                DynamicDataBuilders.DynamicDataValue.fromString("Note about day"))
        .build()
        // ...
    
        return Futures.immediateFuture(Tile.Builder()
            // Set resources, timeline, and other tile properties.
            .setState(state)
            .build()
        )
    

    Java

    @Override
    protected ListenableFuture<Tile> onTileRequest(
                ListenableFuture<Tile> {
        State state = new State.Builder()
            .addKeyToValueMapping(KEY_WATER_INTAKE,
                DynamicDataBuilders.DynamicDataValue.fromInt(200))
            .addKeyToValueMapping(KEY_NOTE,
                DynamicDataBuilders.DynamicDataValue.fromString("Note about day"))
        .build();
        // ...
    
        return Futures.immediateFuture(Tile.Builder()
            // Set resources, timeline, and other tile properties.
            .setState(state)
            .build()
        );
    }
    
  3. Khi bạn tạo bố cục, ở vị trí mà bạn muốn hiện dữ liệu này từ trạng thái, hãy sử dụng một đối tượng loại Dynamic*. Bạn cũng có thể gọi animate() để hiện một ảnh động từ giá trị trước đó đến giá trị hiện tại:

    Kotlin

    DynamicInt32.from(KEY_WATER_INTAKE).animate()
    

    Java

    DynamicInt32.from(KEY_WATER_INTAKE).animate();
    
  4. Khi cần, bạn cũng có thể cập nhật trạng thái bằng các giá trị mới. Đây có thể là một phần của LoadAction của thẻ thông tin.

    Trong ví dụ sau, giá trị lượng nước uống được cập nhật thành 400:

    Kotlin

    state.addKeyToValueMapping(KEY_WATER_INTAKE,
            DynamicDataBuilders.DynamicDataValue.fromInt(400))
    

    Java

    state.addKeyToValueMapping(KEY_WATER_INTAKE,
            DynamicDataBuilders.DynamicDataValue.fromInt(400));