remember,rememberSaveablevəmutableStateOf-un fərqini izah etmək- Vəziyyəti yuxarı qaldırıb vəziyyətsiz (stateless) composable yazmaq
- ViewModel-də
StateFlowilə ekran vəziyyətini saxlamaq və Compose-da oxumaq - Birtərəfli məlumat axınını və MVVM qatlarını təsvir etmək
Leyla viktorina tətbiqində üçüncü suala çatıb və telefonu yan çevirir — hesab sıfırlanır, o isə yenidən başlamalı olur. Belə səhvlərin hamısının kökü eynidir: vəziyyət (state) düzgün yerdə saxlanmayıb. Vəziyyət zamanla dəyişə bilən və ekrana təsir edən istənilən qiymətdir: yazılan mətn, açarın vəziyyəti, yüklənən siyahı, hesab. Bu dərsdə onu harada və necə saxlamağı öyrənəcəksən.
remember və mutableStateOf
Compose yalnız müşahidə olunan vəziyyətin dəyişməsini görür. mutableStateOf(...) belə qiymət yaradır: onu dəyişəndə Compose həmin qiyməti oxuyan funksiyaları yenidən çağırır (recomposition). remember { } isə qiyməti yenidən kompozisiyalar arasında yadda saxlayır; onsuz funksiya hər çağırışda sıfırdan başlayardı. by açar sözü .value yazmadan işləməyə imkan verir.
@Composable
fun Counter() {
var count = 0
Button(onClick = { count++ }) {
Text("Clicked $count times")
}
}@Composable
fun Counter() {
var count by rememberSaveable { mutableIntStateOf(0) }
Button(onClick = { count++ }) {
Text("Clicked $count times")
}
}count artır, amma Compose bundan xəbər tutmur və düymədə həmişə 0 qalır. Sağda hər toxunuş ekranı yeniləyir, qiymət isə ekran döndəriləndə də qorunur.Vəziyyəti yuxarı qaldırmaq
Vəziyyəti composable-ın içindən onu çağıran funksiyaya köçürmək. Composable qiyməti parametr kimi alır, dəyişiklik istəyini isə lambda ilə yuxarı bildirir. Belə funksiya vəziyyətsiz (stateless) olur: onu yoxlamaq, önizləmək və təkrar istifadə etmək asandır.
@Composable
fun CounterScreen() {
var count by rememberSaveable { mutableIntStateOf(0) }
Counter(count = count, onIncrement = { count++ })
}
@Composable
fun Counter(count: Int, onIncrement: () -> Unit, modifier: Modifier = Modifier) {
Button(onClick = onIncrement, modifier = modifier) {
Text("Clicked $count times")
}
}CounterScreen vəziyyətin sahibidir, Counter isə sadəcə onu göstərir və toxunuşu bildirir.ViewModel və StateFlow
ViewModel ekranın məlumatını və məntiqini saxlayan sinifdir. O, ekran döndəriləndə yenidən yaradılmır, ona görə hesab itmir. Vəziyyəti xaricə StateFlow ilə veririk — bu, həmişə cari qiyməti olan və dəyişiklikləri yayımlayan axındır. İçəridə dəyişə bilən MutableStateFlow gizlədilir, xaricə isə yalnız oxunan StateFlow açılır.
data class QuizUiState(
val question: Int = 1,
val score: Int = 0,
val finished: Boolean = false
)
class QuizViewModel : ViewModel() {
private val _uiState = MutableStateFlow(QuizUiState())
val uiState: StateFlow<QuizUiState> = _uiState.asStateFlow()
fun answer(correct: Boolean) {
_uiState.update { state ->
val next = state.question + 1
state.copy(
question = next,
score = if (correct) state.score + 1 else state.score,
finished = next > 5
)
}
}
}data class-dadır; update onu atomar şəkildə yeni surətlə əvəz edir.@Composable
fun QuizScreen(viewModel: QuizViewModel = viewModel()) {
val state by viewModel.uiState.collectAsStateWithLifecycle()
Column(modifier = Modifier.padding(16.dp)) {
if (state.finished) {
Text("Your score: ${state.score} / 5")
} else {
Text("Question ${state.question} of 5")
Button(onClick = { viewModel.answer(correct = true) }) { Text("Correct") }
Button(onClick = { viewModel.answer(correct = false) }) { Text("Wrong") }
}
}
}viewModel() funksiyası ekran üçün ViewModel-i yaradır və ya mövcud olanı qaytarır. collectAsStateWithLifecycle() axını Compose vəziyyətinə çevirir və tətbiq arxa planda olanda toplamanı dayandırır. Bu funksiyalar lifecycle-viewmodel-compose və lifecycle-runtime-compose kitabxanalarındadır.
- 1Kataloqa əlavə et
gradle/libs.versions.tomlfaylında[libraries]bölməsinə iki sətir yaz:androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycleRuntimeKtx" }androidx-lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycleRuntimeKtx" } - 2Modula qoş
app/build.gradle.kts-dədependenciesblokunaimplementation(libs.androidx.lifecycle.viewmodel.compose)vəimplementation(libs.androidx.lifecycle.runtime.compose)əlavə et. - 3Sinxronlaşdır və import et
Sync Nowbas, sonra qırmızı görünənviewModelvəcollectAsStateWithLifecycleüzərindəAlt+Enterbasıbimportseç.
Birtərəfli axın və MVVM
Yuxarıdakı kodda məlumat bir dairə üzrə hərəkət edir: ekran vəziyyəti göstərir → istifadəçi düyməyə basır → ekran ViewModel-ə hadisə göndərir (answer) → ViewModel yeni vəziyyət yaradır → ekran onu göstərir. Buna birtərəfli məlumat axını (UDF) deyilir. Vəziyyəti yalnız bir yer dəyişdiyi üçün səhvləri tapmaq asanlaşır. Bu məntiqi adi Kotlin ilə də yoxlamaq olar:
data class CounterState(val count: Int = 0, val message: String = "")
sealed interface CounterEvent {
data object Increment : CounterEvent
data object Reset : CounterEvent
}
fun reduce(state: CounterState, event: CounterEvent): CounterState = when (event) {
CounterEvent.Increment -> state.copy(
count = state.count + 1,
message = if (state.count + 1 >= 3) "Great streak!" else ""
)
CounterEvent.Reset -> CounterState()
}
fun main() {
var state = CounterState()
val events = listOf(CounterEvent.Increment, CounterEvent.Increment, CounterEvent.Increment, CounterEvent.Reset)
for (event in events) {
state = reduce(state, event)
println("$event -> $state")
}
}Increment -> CounterState(count=1, message=) Increment -> CounterState(count=2, message=) Increment -> CounterState(count=3, message=Great streak!) Reset -> CounterState(count=0, message=)
| MVVM qatı | Vəzifəsi | Nümunə |
|---|---|---|
| Model (məlumat) | məlumatı internetdən və ya verilənlər bazasından alır və saxlayır | LessonRepository |
| ViewModel | ekran vəziyyətini saxlayır, hadisələri emal edir | QuizViewModel |
| View (görünüş) | vəziyyəti göstərir, hadisələri ViewModel-ə ötürür | QuizScreen |
Context-i birbaşa saxlamamalıdır.Cmd+Option+M)Ctrl+Alt+MOption+F7)Alt+F7Cmd+F12)Ctrl+F12Əsas fikirlər
- Compose yalnız
mutableStateOfkimi müşahidə olunan vəziyyətin dəyişməsini görür;rememberonu yenidən kompozisiyalar arasında saxlayır. rememberSaveablesadə qiymətləri ekran döndəriləndə də qoruyur; ekranın əsas məlumatı ViewModel-də saxlanır.- Vəziyyəti qaldır:
valueaşağı enir,onValueChangekimi hadisələr yuxarı qalxır. - ViewModel vəziyyəti gizli
MutableStateFlow-da saxlayır və açıqStateFlowkimi verir; ekran onucollectAsStateWithLifecycle()ilə oxuyur. - MVVM: Model məlumatı verir, ViewModel vəziyyəti idarə edir, View onu göstərir — məlumat bir istiqamətdə hərəkət edir.
Özünü yoxla
10 sual. Hər düzgün cavab XP qazandırır.
remember { mutableStateOf(0) } ilə saxlanan qiymətə nə olur?