Stateful ViewModel

Mar 13 2023
วันนี้ฉันต้องการแบ่งปันตัวแปรคลาส ViewModel ที่มีประโยชน์ซึ่งฉันได้เขียนขึ้นและฉันใช้มาระยะหนึ่งแล้ว ในการจัดการและเปิดเผยสถานะจาก ViewModel เราสามารถใช้ StateFlow api ยอดนิยมของ Kotlins ได้
ภาพถ่ายโดย Kelly Sikkema บน Unsplash

วันนี้ฉันต้องการแบ่งปัน ตัวแปรคลาส ViewModel ที่มีประโยชน์ ซึ่งฉันได้เขียนขึ้นและฉันใช้มาระยะหนึ่งแล้ว

ในการจัดการและเปิดเผยสถานะจากViewModel เราสามารถใช้ StateFlow api ยอดนิยมของ Kotlins ได้

ให้เราแสดงสถานะ UI ของเราด้วยคลาสข้อมูลด้านล่าง:

data class UiState(
    val isLoading: Boolean = false,
    val hasError: Boolean = false,
    val data: ScreenData? = null,
)

ในการเปิดเผยสถานะข้างต้นกับ UI เราใช้คลาสที่ขยาย ViewModel:

class ScreenViewModel() : ViewModel() {

    private val _uiState = MutableStateFlow(UiState())
    val uiState: StateFlow<UiState> = _uiState.asStateFlow()

    suspend fun fetchData() {
        _uiState.update { state ->
            state.copy(
                isLoading = true,
                hasError = false
            )
        }

        val fetchedData = fetchDataFromNetwork()
        val failed = fetchedData is Error
        val data = fetchedData as? Data

        _uiState.update { state ->
            state.copy(
                isLoading = false,
                hasError = failed,
                data = data,
            )
        }
    }

}

สมมติว่าเราต้องการฟังก์ชันอื่นที่จะอัปเดตข้อมูล จากนั้นเราจะเขียนดังนี้:

suspend fun updateData(newData: Data) {
    _uiState.update { state ->
        state.copy(
            isLoading = true,
            hasError = false
        )
    }

    val update = updateAndGetData(newData)
    val failed = update is Error
    val data = update as? Data

    _uiState.update { state ->
        state.copy(
            isLoading = false,
            hasError = failed,
            data = data,
        )
    }
}

หลายๆ คนคงเคยทำมาแล้ว ฉันใช้รูปแบบนี้หลายครั้งแล้ว ดังนั้นฉันจึงตัดสินใจเขียน ViewModel ทั่วไปเพิ่มเติม ฉันเรียกมันว่าStatefulViewModel:

open class StatefulViewModel<T>(initState: T): ViewModel() {

    private val _uiState = MutableStateFlow(initState)
    val uiState = _uiState.asStateFlow()

    protected fun updateState(f: T.() -> T) {
        _uiState.update(f)
    }

    protected fun updateState(newState: T) {
        _uiState.value = newState
    }

    protected val state: T
        get() = _uiState.value
}

เมื่อใช้คลาสใหม่นี้ScreenViewModel ที่เขียนไว้ข้างต้นของเรา สามารถปรับเปลี่ยนโครงสร้างใหม่ได้ดังนี้:

class ScreenViewModel : StatefulViewModel<UiState>(UiState()) {

    suspend fun fetchData() {
        updateState {
            copy(isLoading = true, hasError = false)
        }

        val fetchedData = fetchDataFromNetwork()
        val failed = fetchedData is Error
        val data = fetchedData as? Data

        updateState {
            copy(isLoading = false, hasError = failed, data = data)
        }
    }

    suspend fun updateData(newData: Data) {
        updateState {
            copy(isLoading = true, hasError = false)
        }

        val update = updateAndGetData()
        val failed = update is Error
        val data = update as? Data

        updateState {
            copy(isLoading = false, hasError = failed, data = data)
        }
    }
    
}

ฉันหวังว่าคุณจะพบว่า คลาส StatefulViewModelมีประโยชน์และใช้ในโครงการต่อไปของคุณ!