MutableState a rekompozíciaVšimol si si, že Composable funkcie sa volajú funkcie? Kto ale túto funkciu vlasne spustí? Odpoveďou je samozrejme JetPack Compose. Problém je, že my chceme aby JetPack Compose zavolal funkciu, keď niečo spravíme my. Existovať tak musí mechanizmus, akým JetPack Compose poprosíme o znovuprekreslenie obrazovky s novými hodnotami.
Znovuprekresleniu hovoríme rekompozícia. Tú JetPack Compose vykoná automaticky, keď sa zmení stav (State) aplikácie.
State si môžeš jednoducho predstaviť ako špeciálne označenú premennú, ktorú JetPack Compose rešpektuje. Ukážme si
rovno, ako vytvoriť takúto premennú:
setContent {
// premenna intState je typu MutableState
// MutableState je podtriedou triedy State
// premennu intState inicializujeme s hodnotou 0
val intState: MutableState<Int> = mutableStateOf(0)
Button(onClick = { intState.value++ }) {
Text("Click me ${intState.value}")
}
}
intState je na začiatku 0 (mutableStateOf(0))value) premennej intState inkrementuje z 0 na 1State (premenná typu MutableState), JetPack Compose znovu zavolá funkciu setContentintState je 1 preto sa text na tlačidle zmení na Click me 1Skoro správne, ale pri zavolaní funkcie setContent sa premenná intState v skutočnosti vytvorí odznova a opäť bude
mať hodnotu 0. Preto potrebujeme ešte JetPack Compose označiť, ktoré premenné nám nemá prepisovať. To zabezpečíme
pomocou funkcie remember nasledovne:
setContent {
val intState = remember { mutableStateOf(0) }
Button(onClick = { intState.value++ }) {
Text("Click me ${intState.value}")
}
}
.valueKotlin poskytuje tzv. delegáty, ktoré nám v tomto konkrétnom prípade pomôžu zbaviť sa .value zápisov. Stačiť nám
bude slovíčko by a správne importy:
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
// ...
setContent {
// zmena "val" na "var" a pouzitie "by"
var intState by remember { mutableStateOf(0) }
Button(onClick = { intState++ }) {
Text("Click me $intState")
}
}
Kedysi sa mi stávalo, že Android Studio nedokázalo doplniť importy a musel som ich pridávať manuálne, preto som ich sem radšej pridal. Za normálnych okolností by malo stačiť
intStateImport operator State.getValueImport operator State.setValueAk nechceš dookola zapisovať by remember { mutableStateOf(???) }, môžeš si napísať vlastnú globálnu funkciu, ktorá
obe tieto operácie (remember a mutableStateOf) zhrnie do jednej funkcie:
@Composable
fun<T> rememberMutableStateOf(initialValue: T): MutableState<T> = remember { mutableStateOf(initialValue) }
a potom ju použiť takto:
var intState by rememberMutableStateOf(0)
Button(onClick = { intState++ }) {
Text("Click me $intState")
}
Bežne to nerobím, ale je pekné myslieť na skrátenie často používaných zápisov.