StateFlow: ตัวเก็บสถานะแบบร้อนสำหรับ UI
ใช้ StateFlow เป็นคอนเทนเนอร์สถานะแบบตอบสนองและสังเกตค่าภายใน ViewModels
StateFlow: ตัวเก็บสถานะแบบร้อนสำหรับ UI เป็นบทเรียน Kotlin Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Kotlin Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน
StateFlow คืออะไร
StateFlow เป็นโฟลว์แบบร้อนที่เก็บสถานะ มีค่าอยู่เสมอ และส่งการอัปเดตไปยังผู้รวบรวมทั้งหมด โดยใช้แทน LiveData ในสถาปัตยกรรม Kotlin สมัยใหม่
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val stateFlow = MutableStateFlow(0) // initial value
println("Current: ${stateFlow.value}")
stateFlow.value = 42
println("Updated: ${stateFlow.value}")
}MutableStateFlow เทียบกับ StateFlow
MutableStateFlow เป็นการนำไปใช้งานแบบแก้ไขได้ที่ใช้ภายใน ให้ผู้สังเกตการณ์ภายนอกเข้าถึง StateFlow (อ่านได้อย่างเดียว) โดยแปลงชนิดหรือใช้ .asStateFlow()
import kotlinx.coroutines.flow.*
class CounterViewModel {
private val _count = MutableStateFlow(0) // mutable internally
val count: StateFlow<Int> = _count.asStateFlow() // read-only externally
fun increment() { _count.value++ }
fun decrement() { _count.value-- }
}การรวบรวม StateFlow
รวบรวม StateFlow เช่นเดียวกับโฟลว์อื่น ๆ ค่าล่าสุดจะถูกส่งออกทันทีเมื่อเริ่มรวบรวม
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val state = MutableStateFlow("loading")
launch {
state.collect { println("State: $it") }
}
delay(50); state.value = "success"
delay(50); state.value = "idle"
delay(50)
coroutineContext.cancelChildren()
}StateFlow รวมค่าที่ซ้ำกัน
StateFlow จะส่งค่าออกมาเฉพาะเมื่อค่ามีการเปลี่ยนแปลง หากกำหนดค่าเดิมสองครั้ง จะมีการส่งออกเพียงครั้งเดียว เพราะจะรวมค่าที่ซ้ำกันติดต่อกัน
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val flow = MutableStateFlow("A")
launch {
flow.collect { println("Received: $it") }
}
delay(50)
flow.value = "A" // no emission — same value
flow.value = "B" // emits
flow.value = "B" // no emission — same value
flow.value = "C" // emits
delay(50)
coroutineContext.cancelChildren()
}StateFlow ใน ViewModel
รูปแบบมาตรฐานของ ViewModel คือให้ตรรกะทางธุรกิจแก้ไข MutableStateFlow แบบส่วนตัว และให้ UI สังเกต StateFlow แบบสาธารณะ
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
sealed class UiState { object Loading : UiState(); data class Success(val data: String) : UiState(); data class Error(val msg: String) : UiState() }
class MyViewModel(scope: CoroutineScope) {
private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
init {
scope.launch {
delay(100) // simulate load
_uiState.value = UiState.Success("Hello!")
}
}
}update() สำหรับการแก้ไขแบบอะตอมิก
ใช้ update { } เพื่ออัปเดตสถานะโดยอาศัยค่าปัจจุบันแบบอะตอมิก ซึ่งสำคัญเมื่อมีการอัปเดตพร้อมกัน
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val counter = MutableStateFlow(0)
List(100) {
launch(Dispatchers.Default) {
counter.update { it + 1 } // thread-safe atomic update
}
}.forEach { it.join() }
println("Counter: ${counter.value}") // 100
}compareAndSet สำหรับการอัปเดตเชิงมองโลกในแง่ดี
compareAndSet(expect, update) จะกำหนดค่าใหม่ก็ต่อเมื่อค่าปัจจุบันตรงกับ expect เหมาะสำหรับการทำงานพร้อมกันเชิงมองโลกในแง่ดี
import kotlinx.coroutines.flow.*
fun main() {
val state = MutableStateFlow("idle")
val changed = state.compareAndSet("idle", "loading")
println("Changed: $changed, Value: ${state.value}") // true, loading
val changed2 = state.compareAndSet("idle", "error") // won't change
println("Changed: $changed2, Value: ${state.value}") // false, loading
}StateFlow เทียบกับ LiveData
StateFlow ทำงานได้โดยไม่ต้องพึ่งวงจรชีวิตของ Android ส่วน LiveData รับรู้วงจรชีวิตแต่ใช้ได้เฉพาะ Android ควรเลือกใช้ StateFlow สำหรับ ViewModels แบบ KMP ที่ใช้ร่วมกัน
import kotlinx.coroutines.flow.*
// StateFlow: pure Kotlin, works in commonMain
// val state = MutableStateFlow("value")
// LiveData: Android-only, lifecycle-aware
// val liveData = MutableLiveData("value")
// In Compose, collect StateFlow with:
// val state by viewModel.uiState.collectAsState()
fun main() { println("StateFlow: multiplatform; LiveData: Android-only") }stateIn: การแปลงโฟลว์เย็นเป็น StateFlow
flow.stateIn(scope, started, initialValue) แปลงโฟลว์เย็นเป็น StateFlow แบบร้อน และใช้การสมัครรับเพียงหนึ่งรายการร่วมกันระหว่างผู้รวบรวมทั้งหมด
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val cold = flow {
println("Fetching...")
delay(100)
emit("data")
}
val hot: StateFlow<String> = cold.stateIn(
scope = this,
started = SharingStarted.Lazily,
initialValue = "loading"
)
launch { hot.collect { println("A: $it") } }
launch { hot.collect { println("B: $it") } }
delay(200)
coroutineContext.cancelChildren()
}กลยุทธ์ SharingStarted
Eagerly: เริ่มทำงานทันที Lazily: เริ่มทำงานเมื่อมีผู้รวบรวมรายแรก WhileSubscribed(stopTimeout): หยุดเมื่อไม่มีผู้รวบรวม และเริ่มใหม่เมื่อมีผู้สมัครรับ
import kotlinx.coroutines.flow.*
// Eagerly: upstream starts right away
// SharingStarted.Eagerly
// Lazily: waits for first subscriber
// SharingStarted.Lazily
// WhileSubscribed: stops 5s after last subscriber
// SharingStarted.WhileSubscribed(5000)
// Typical ViewModel usage:
// val uiState = repo.dataFlow.stateIn(viewModelScope, WhileSubscribed(5000), Loading)การสังเกตสถานะที่คำนวณต่อ
สร้าง StateFlow ใหม่จาก StateFlow ที่มีอยู่ด้วย map + stateIn โฟลว์ที่สร้างขึ้นจะอัปเดตทุกครั้งที่แหล่งข้อมูลเปลี่ยนแปลง
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val count = MutableStateFlow(5)
val doubled = count.map { it * 2 }.stateIn(this, SharingStarted.Eagerly, 10)
println(doubled.value) // 10
count.value = 7
delay(50)
println(doubled.value) // 14
coroutineContext.cancelChildren()
}ตรวจสอบความเข้าใจอย่างรวดเร็ว
StateFlow ทำอย่างไรเมื่อกำหนดค่าเดิมสองครั้ง
ทบทวน
StateFlow เป็นโฟลว์แบบร้อนที่มีค่าอยู่เสมอและรวมค่าที่ซ้ำกัน ใช้ MutableStateFlow ภายในและเปิดเผย StateFlow ภายนอก ใช้ update() สำหรับการแก้ไขพร้อมกัน และใช้ stateIn() เพื่อแปลงโฟลว์เย็น
เรียนรู้ Kotlin ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 51
- บทเรียน
- 203
คำถามที่พบบ่อย
บทเรียน “StateFlow: ตัวเก็บสถานะแบบร้อนสำหรับ UI” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “StateFlow: ตัวเก็บสถานะแบบร้อนสำหรับ UI” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Kotlin Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “StateFlow: ตัวเก็บสถานะแบบร้อนสำหรับ UI”
ใช้ StateFlow เป็นคอนเทนเนอร์สถานะแบบตอบสนองและสังเกตค่าภายใน ViewModels คุณปฏิบัติ Kotlin Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Kotlin Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Kotlin Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน
บทเรียน “StateFlow: ตัวเก็บสถานะแบบร้อนสำหรับ UI” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Kotlin Academy นี้ได้ไหม
ได้ บทเรียน Kotlin Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- StateFlow: ตัวเก็บสถานะแบบร้อนสำหรับ UI
- SharedFlow: บัสเหตุการณ์และเหตุการณ์แบบครั้งเดียว
- แปลง Cold Flow เป็น Hot ด้วย shareIn และ stateIn
- ทดสอบ StateFlow และ SharedFlow ด้วย Turbine