ViewModel yang Berstatus

Mar 13 2023
Hari ini saya ingin berbagi dengan Anda varian kelas ViewModel praktis yang telah saya tulis dan telah saya gunakan selama beberapa waktu. Untuk mengelola dan mengekspos status dari ViewModel, seseorang dapat menggunakan api populer Kotlins, StateFlow.
Foto oleh Kelly Sikkema di Unsplash

Hari ini saya ingin berbagi dengan Anda varian kelas ViewModel praktis yang telah saya tulis dan telah saya gunakan selama beberapa waktu.

Untuk mengelola dan mengekspos status dari ViewModel , seseorang dapat menggunakan api populer Kotlins, StateFlow .

Mari kita wakili keadaan UI kita dengan kelas data di bawah ini:

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

Untuk mengekspos status di atas ke UI, kami menggunakan kelas yang memperluas 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,
            )
        }
    }

}

Misalkan kita membutuhkan fungsi lain yang akan memperbarui data, maka kita akan menulis sesuatu seperti:

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,
        )
    }
}

Seperti yang mungkin telah Anda lakukan, saya telah menggunakan pola ini berkali-kali. Jadi saya memutuskan untuk menulis ViewModel generik yang diperluas, saya menyebutnya 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
}

Dengan menggunakan kelas baru ini, ScreenViewModel yang ditulis di atas dapat direfaktorisasi seperti di bawah ini:

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)
        }
    }
    
}

Saya harap Anda menemukan kelas StatefulViewModel berguna dan menggunakannya dalam proyek Anda berikutnya!