Kotlin Academy · บทเรียน

StateFlow: ตัวเก็บสถานะแบบร้อนสำหรับ UI

ใช้ StateFlow เป็นคอนเทนเนอร์สถานะแบบตอบสนองและสังเกตค่าภายใน ViewModels

บทเรียน 1 จาก 413 ขั้นตอน

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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. StateFlow: ตัวเก็บสถานะแบบร้อนสำหรับ UI
  2. SharedFlow: บัสเหตุการณ์และเหตุการณ์แบบครั้งเดียว
  3. แปลง Cold Flow เป็น Hot ด้วย shareIn และ stateIn
  4. ทดสอบ StateFlow และ SharedFlow ด้วย Turbine
← กลับไปที่ Kotlin Academy