Pokazuj dynamiczne aktualizacje w kafelkach

Od wersji 1.2 kafelków możesz przesyłać strumieniowo aktualizacje danych platformy za pomocą wyrażenia dynamiczne. Następnie możesz powiązać te aktualizacje z animacjami. w swoich kafelkach. Aplikacja aktualizuje tę wartość co sekundę.

Dzięki zastosowaniu wyrażeń dynamicznych nie musisz odświeżać całego kafelka, gdy jest zmian treści. Aby zwiększyć zaangażowanie kafelków, włącz animację tych dynamicznych obiektów.

Powiąż wyrażenia dynamiczne ze źródłami danych

androidx.wear.protolayout i androidx.wear.protolayout.material przestrzenie nazw zawierają wiele klas, których pola przyjmują wyrażenia dynamiczne. Oto kilka przykładów:

Aby użyć wyrażenia dynamicznego jako możliwej wartości elementu w kafelku, użyj funkcji odpowiedni typ właściwości dynamicznej *Prop i przekazać dane. źródło do klasy konstruktora klasy usługi dynamicznej typu setDynamicValue() .

Kafelki obsługują te typy właściwości dynamicznych:

Jeśli używasz wyrażenia dynamicznego, które wpływa na wymiary fizyczne – dowolna wartość w argumencie kafelka oprócz koloru – musisz też określić zestaw powiązanych ograniczeń, takich jak w formacie ciągu znaków. Dzięki tym ograniczeniom system renderowania może określić maksymalna ilość miejsca, jaką dana wartość może zająć na kafelku. Zwykle określaj te ograniczenia na poziomie elementu, a nie wyrażenia dynamicznego poziomu za pomocą metody, która rozpoczyna się od setLayoutConstraintsForDynamic*.

Fragment kodu poniżej pokazuje, jak wyświetlać aktualizacje tętna za pomocą 3 cyfry, z wartością zastępczą --:

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

Używaj małej liczby wyrażeń w jednym kafelku

Wear OS nakłada limit liczby wyrażeń, które można dodać do jednego kafelka użytkowników. Jeśli kafelek zawiera zbyt wiele wyrażeń dynamicznych, wartości dynamiczne są ignorowany, a system wraca do wartości statycznych, które podasz odpowiednich typów usług dynamicznych.

Możesz bezpiecznie dodać do kafelka poniższy zestaw wyrażeń, ponieważ nie ma zbyt wielu wyrażeń. W związku z tym kafelek działa prawidłowo:

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

Ten kafelek może mieć jednak zbyt wiele wyrażeń:

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

Skonsoliduj dane dynamiczne w obiekcie stanu

Możesz skonsolidować najnowszy zestaw aktualizacji ze źródeł danych w stan, który jest przekazywany do kafelka w celu renderowania wartości.

Aby użyć informacji o stanie w kafelkach, wykonaj te czynności:

  1. Utwórz zestaw kluczy reprezentujących różne wartości stanu. W tym przykładzie tworzymy klucze do picia wody i nutę:

    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. W ramach implementacji kodu onTileRequest() wywołaj setState() i ustal początkowe mapowania z każdego klucza na określoną wartość danych dynamicznych:

    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. Podczas tworzenia układu – w miejscu, w którym chcesz wyświetlać te dane ze stanu, użyj obiektu typu Dynamic*. Możesz też zadzwonić pod numer animate(), aby pokazana jest animacja zmiany poprzedniej wartości na obecną:

    Kotlin

    DynamicInt32.from(KEY_WATER_INTAKE).animate()
    

    Java

    DynamicInt32.from(KEY_WATER_INTAKE).animate();
    
  4. W razie potrzeby możesz też zaktualizować stan o nowe wartości. Może to być w obszarze LoadAction kafelka.

    W tym przykładzie wartość spożycia wody jest aktualizowana na 400:

    Kotlin

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

    Java

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