在資訊方塊中顯示動態更新內容

從 Tiles 1.2 開始,您可以使用動態運算式串流更新平台資料。透過這種方式,您可以將這些更新內容與資訊方塊中的動畫建立關聯。這樣一來,您的應用程式每秒都能更新這個值。

只要使用動態運算式,當資訊方塊內容變更時,就不必重新整理整個資訊方塊。如要為資訊方塊打造更吸引人的體驗,可以為這些動態物件加上動畫效果。

將動態運算式與資料來源建立關聯

androidx.wear.protolayoutandroidx.wear.protolayout.material 命名空間包含許多類別,其欄位可接受動態運算式。以下提供幾個範例:

如要使用動態運算式做為資訊方塊中某個元素可能的值,請使用該元素的對應 *Prop 動態屬性類型,然後將資料來源傳入動態屬性類型的建構工具類別 setDynamicValue() 方法。

資訊方塊支援下列動態屬性類型:

如果使用的動態運算式會影響實體維度 (資訊方塊中的任何值,但顏色值除外),必須同時指定一組相關限制條件,例如字串格式。這些限制條件可讓系統轉譯器決定資訊方塊中某個值可占用的空間上限。您通常可以呼叫開頭為 setLayoutConstraintsForDynamic* 的方法,在元素層級 (而不是動態運算式層級) 指定這些限制條件。

下列程式碼片段說明如何使用 3 位數 (備用值為 --) 顯示更新的心率:

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

在單一資訊方塊中使用少量運算式

Wear OS 對單一資訊方塊可擁有的運算式數量設有限制。如果資訊方塊內含的動態運算式總數過多,系統會忽略這些動態值,改回使用您提供給各個動態屬性類型的靜態值。

由於下列運算式的總數不足,您可以放心將以下這組運算式加入資訊方塊。這樣一來,資訊方塊就會正常運作:

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");

但是,以下資訊方塊可能含有數量過多的運算式:

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

將動態資料合併為狀態物件

您可以將資料來源提供的最新一組更新內容合併為「狀態」,然後傳送至資訊方塊以進行值轉譯。

如要在資訊方塊中使用狀態資訊,請完成下列步驟:

  1. 建立一組鍵,代表資訊方塊的不同狀態值。以下範例建立了代表飲水量和附註的鍵:

    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. onTileRequest() 實作中,呼叫 setState() 並建立每個鍵與特定動態資料值的初始對應:

    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. 建立版面配置時,在要顯示狀態資料的位置,使用 Dynamic* 類型物件。您也可以呼叫 animate(),顯示從前一個值轉換成目前值的動畫:

    Kotlin

    DynamicInt32.from(KEY_WATER_INTAKE).animate()
    

    Java

    DynamicInt32.from(KEY_WATER_INTAKE).animate();
    
  4. 如有需要,您也可以將狀態更新為新的值。這可以透過資訊方塊的 LoadAction 執行。

    在以下範例中,飲水量值會更新為 400

    Kotlin

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

    Java

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