Dynamische Updates in Kacheln anzeigen

Ab Tiles 1.2 können Sie Plattformdatenaktualisierungen mithilfe von dynamischen Ausdrücken streamen. Anschließend kannst du diese Aktualisierungen mit Animationen in deinen Kacheln verknüpfen. Deine App erhält jede Sekunde Updates auf diesen Wert.

Wenn Sie dynamische Ausdrücke verwenden, müssen Sie nicht die gesamte Kachel aktualisieren, wenn sich ihr Inhalt ändert. Animieren Sie diese dynamischen Objekte, um die Kacheln ansprechender zu gestalten.

Dynamische Ausdrücke mit Datenquellen verknüpfen

Die Namespaces androidx.wear.protolayout und androidx.wear.protolayout.material enthalten viele Klassen, deren Felder dynamische Ausdrücke akzeptieren. Hier einige Beispiele:

Wenn Sie einen dynamischen Ausdruck als möglichen Wert für ein Element in Ihrer Kachel nutzen möchten, verwenden Sie den entsprechenden dynamischen Eigenschaftstyp *Prop des Elements und übergeben Sie die Datenquelle an die Methode setDynamicValue() der Builder-Klasse des dynamischen Eigenschaftstyps.

Kacheln unterstützen die folgenden dynamischen Eigenschaftstypen:

Wenn Sie einen dynamischen Ausdruck verwenden, der sich auf physische Dimensionen auswirkt – jeden Wert in einer Kachel mit Ausnahme der Farbe –, müssen Sie auch eine Reihe zugehöriger Einschränkungen angeben, z. B. ein Stringformat. Anhand dieser Einschränkungen kann der System-Renderer den maximalen Platz bestimmen, den ein Wert auf Ihrer Kachel einnehmen kann. Normalerweise geben Sie diese Einschränkungen auf Elementebene und nicht auf Ebene dynamischer Ausdrücke an, indem Sie eine Methode aufrufen, die mit setLayoutConstraintsForDynamic* beginnt.

Das folgende Code-Snippet zeigt, wie Aktualisierungen einer Herzfrequenz mithilfe von drei Ziffern mit einem Fallback-Wert von -- angezeigt werden:

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

Eine geringe Anzahl von Ausdrücken innerhalb einer einzelnen Kachel verwenden

Wear OS beschränkt die Anzahl der Ausdrücke, die eine einzelne Kachel enthalten kann. Wenn eine Kachel zu viele dynamische Ausdrücke enthält, werden dynamische Werte ignoriert und das System greift auf die statischen Werte zurück, die Sie für die jeweiligen dynamischen Attributtypen angeben.

Sie können einer Kachel bedenkenlos die folgenden Ausdrücke hinzufügen, da es nicht viele Ausdrücke insgesamt gibt. Daher verhält sich die Kachel korrekt:

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

Diese Kachel kann jedoch zu viele Ausdrücke enthalten:

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

Dynamische Daten in einem Statusobjekt konsolidieren

Sie können die neuesten Aktualisierungen aus Datenquellen in einem Status konsolidieren, den Sie zum Rendern von Werten an Ihre Kachel übergeben.

So verwenden Sie Statusinformationen in Ihren Kacheln:

  1. Richten Sie einen Satz von Schlüsseln ein, die die verschiedenen Werte des Status Ihrer Kachel darstellen. In diesem Beispiel werden Schlüssel für die Wasseraufnahme und ein Hinweis erstellt:

    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. Rufen Sie in der Implementierung von onTileRequest() setState() auf und richten Sie erste Zuordnungen von jedem Schlüssel zu einem bestimmten dynamischen Datenwert ein:

    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. Wenn Sie das Layout an einer Stelle erstellen, an der diese Daten angezeigt werden sollen, verwenden Sie ein Objekt des Typs Dynamic*. Sie können auch animate() aufrufen, um eine Animation vom vorherigen bis zum aktuellen Wert anzuzeigen:

    Kotlin

    DynamicInt32.from(KEY_WATER_INTAKE).animate()
    

    Java

    DynamicInt32.from(KEY_WATER_INTAKE).animate();
    
  4. Bei Bedarf können Sie den Status auch mit neuen Werten aktualisieren. Dies kann Teil des LoadAction einer Kachel sein.

    In diesem Beispiel wird der Wert für die Wasseraufnahme in 400 aktualisiert:

    Kotlin

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

    Java

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