Menampilkan pembaruan dinamis dalam kartu

Mulai Kartu 1.2, Anda dapat melakukan streaming pembaruan data platform menggunakan ekspresi dinamis. Kemudian, Anda dapat mengaitkan pembaruan ini dengan animasi di kartu Anda. Aplikasi Anda mendapatkan pembaruan untuk nilai ini setiap detik.

Dengan menggunakan ekspresi dinamis, Anda tidak perlu me-refresh seluruh kartu saat kontennya berubah. Untuk membuat pengalaman yang lebih menarik di kartu, animasikan objek dinamis tersebut.

Mengaitkan ekspresi dinamis dengan sumber data

Namespace androidx.wear.protolayout dan androidx.wear.protolayout.material berisi banyak class yang kolomnya menerima ekspresi dinamis. Beberapa contohnya meliputi:

Untuk menggunakan ekspresi dinamis sebagai kemungkinan nilai untuk elemen dalam kartu Anda, gunakan jenis properti dinamis *Prop yang sesuai pada elemen dan teruskan sumber data ke metode setDynamicValue() class builder jenis properti dinamis.

Kartu mendukung jenis properti dinamis ini:

Saat menggunakan ekspresi dinamis yang memengaruhi dimensi fisik—nilai apa pun dalam kartu kecuali warna—Anda juga harus menentukan kumpulan batasan terkait, seperti format string. Batasan ini memungkinkan perender sistem menentukan jumlah ruang maksimum yang dapat menempati nilai dalam kartu Anda. Biasanya, Anda akan menentukan batasan ini pada tingkat elemen, bukan pada tingkat ekspresi dinamis, dengan memanggil metode yang dimulai dengan setLayoutConstraintsForDynamic*.

Cuplikan kode berikut menunjukkan cara menampilkan pembaruan pada detak jantung menggunakan 3 digit, dengan nilai penggantian --:

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

Menggunakan sejumlah kecil ekspresi dalam satu kartu

Wear OS menetapkan batas jumlah ekspresi yang dapat dimiliki satu kartu. Jika kartu berisi terlalu banyak ekspresi dinamis total, nilai dinamis akan diabaikan, dan sistem akan kembali ke nilai statis yang Anda berikan ke jenis properti dinamis masing-masing.

Anda dapat dengan aman menambahkan kumpulan ekspresi berikut ke kartu, karena tidak ada banyak ekspresi total. Oleh karena itu, kartu berperilaku dengan benar:

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

Namun, kartu ini mungkin memiliki terlalu banyak ekspresi:

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

Menggabungkan data dinamis ke dalam objek status

Anda dapat menggabungkan kumpulan pembaruan terbaru dari sumber data ke dalam status, yang akan diteruskan ke kartu untuk rendering nilai.

Untuk menggunakan informasi status di kartu Anda, selesaikan langkah-langkah berikut:

  1. Tetapkan kumpulan kunci yang mewakili berbagai nilai dari status kartu Anda. Contoh ini membuat kunci untuk asupan air dan catatan:

    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. Dalam penerapan onTileRequest(), panggil setState() dan tetapkan pemetaan awal dari setiap kunci ke nilai data dinamis tertentu:

    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. Saat Anda membuat tata letak, di tempat yang diinginkan untuk menampilkan data ini dari status, gunakan objek jenis Dynamic*. Anda juga dapat memanggil animate() untuk menampilkan animasi dari nilai sebelumnya ke nilai saat ini:

    Kotlin

    DynamicInt32.from(KEY_WATER_INTAKE).animate()
    

    Java

    DynamicInt32.from(KEY_WATER_INTAKE).animate();
    
  4. Jika diperlukan, Anda juga dapat memperbarui status dengan nilai baru. Status ini dapat menjadi bagian dari LoadAction kartu.

    Dalam contoh ini, nilai asupan air diperbarui menjadi 400:

    Kotlin

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

    Java

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