Pokazuj dynamiczne aktualizacje w kafelkach

Od wersji 1.2 aplikacji Tiles możesz przesyłać strumieniowo aktualizacje danych platformy za pomocą wyrażeń dynamicznych. Następnie możesz powiązać te aktualizacje z animowanymi kafelkami. Aplikacja otrzymuje aktualizacje tej wartości co sekundę.

Dzięki wyrażeniom dynamicznym nie musisz odświeżać całej płytki, gdy zmienia się jej zawartość. Aby zwiększyć atrakcyjność kafelków, umieść na nich dynamiczne obiekty.

Powiązanie wyrażeń dynamicznych ze źródłami danych

Przestrzeń nazw androidx.wear.protolayoutandroidx.wear.protolayout.material zawiera wiele klas, których pola akceptują wyrażenia dynamiczne. Oto kilka przykładów:

Aby użyć wyrażenia dynamicznego jako możliwej wartości elementu na karcie, użyj odpowiedniego typu właściwości dynamicznej *Propelementu i przekaż źródło danych do metody setDynamicValue() klasy konstruktora typu właściwości dynamicznej.

Kafelki obsługują te typy usług dynamicznych:

Jeśli używasz wyrażenia dynamicznego, które wpływa na wymiary fizyczne (dowolna wartość w płytce z wyjątkiem koloru), musisz też określić zestaw powiązanych ograniczeń, np. w formacie ciągu znaków. Te ograniczenia umożliwiają systemowi renderowania określenie maksymalnej ilości miejsca, jaką dana wartość może zajmować na kafelku. Zwykle te ograniczenia określasz na poziomie elementu, a nie wyrażenia dynamicznego, wywołując metodę, która zaczyna się od setLayoutConstraintsForDynamic*.

Ten fragment kodu pokazuje, jak wyświetlać tętno z aktualizacjami w postaci 3 cyfr, z wartością zastępczą --:

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(),
                        TypeBuilders.StringLayoutConstraint.Builder("000").build(),
                    )
                        .build()
                )
            )
            .build()
    )

Używanie niewielkiej liczby wyrażeń na jednej karcie

Wear OS nakłada limit liczby wyrażeń, które może zawierać pojedyncza ikona. Jeśli kafelek zawiera zbyt wiele wyrażeń dynamicznych, wartości dynamiczne są ignorowane, a system używa wartości statycznych podanych przez Ciebie dla odpowiednich typów usług dynamicznych.

Konsolidowanie danych dynamicznych w obiekcie stanu

Możesz scalić najnowszy zestaw aktualizacji ze źródeł danych w stanie, który przekazujesz do swojej płytki na potrzeby renderowania wartości.

Aby używać informacji o stanie na kafelkach, wykonaj te czynności:

  1. Utwórz zestaw kluczy, które reprezentują różne wartości stanu kafelka. W tym przykładzie tworzymy klucze dotyczące spożycia wody i notatki:

    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 implementacji funkcji onTileRequest() wywołaj funkcję setState() i ustaw początkowe mapowania każdego klucza do konkretnej wartości 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 z stanu, użyj obiektu typu Dynamic*. Możesz też wywołać funkcję animate(), aby wyświetlić animację przejścia od poprzedniej wartości do bieżącej:

    Kotlin

    DynamicInt32.from(KEY_WATER_INTAKE).animate()

    Java

    DynamicInt32.from(KEY_WATER_INTAKE).animate();
  4. W razie potrzeby możesz też zaktualizować stan za pomocą nowych wartości. Może ona być częścią LoadAction.

    W tym przykładzie wartość spożycia wody została zaktualizowana na 400:

    Kotlin

    val loadAction = LoadAction.Builder()
        .setRequestState(
            State.Builder()
                .addKeyToValueMapping(
                    KEY_WATER_INTAKE,
                    DynamicDataBuilders.DynamicDataValue.fromInt(400)
                )
                .build()
        )
        .build()

    Java

    LoadAction loadAction = new LoadAction.Builder()
        .setRequestState(
            new State.Builder()
                .addKeyToValueMapping(
                    KEY_WATER_INTAKE,
                    DynamicDataBuilders.DynamicDataValue.fromInt(400)
                ).build()
        ).build();