Which one is standard for toggling `isLoading` val...
# android
r
Which one is standard for toggling
isLoading
value before and after a network call and has no issues. Option 1:
Copy code
viewModelScope.launch {
    _uiState.update { it.copy(isLoading = true) }
    val result = getSomethingUseCase()
    if (result.isSuccess) {
        _uiState.update {
            it.copy(isLoading = false, data = result.getOrDefault(emptyList()))
        }
    } else {
        _uiState.update {
            it.copy(isLoading = false, errorMessage = Error.unknownError())
        }
    }
}
Problem: have to isLoading = false everything let's say I handle multiple types of error then with when block. See more in the thread 🧵
Option 2:
Copy code
viewModelScope.launch {
    _uiState.update { it.copy(isLoading = true) }
    val result = getSomethingUseCase()
    _uiState.update { it.copy(isLoading = false) }
    if (result.isSuccess) {
        _uiState.update {
            it.copy(data = result.getOrDefault(emptyList()))
        }
    } else {
        _uiState.update {
            it.copy(errorMessage = Error.unknownError())
        }
    }
}
isLoading = false just after the network call even before updating the state
Option 3:
Copy code
viewModelScope.launch {
    try {
        _uiState.update { it.copy(isLoading = true) }
        val result = getSomethingUseCase()
        if (result.isSuccess) {
            _uiState.update {
                it.copy(data = result.getOrDefault(emptyList()))
            }
        } else {
            _uiState.update { it.copy(errorMessage = Error.unknownError()) }
        }
    } finally {
        _uiState.update { it.copy(isLoading = false) }
}
Using try and finally Problem: Introducing an unnecessary try and finally block
f
I use a sealed interface
plus1 3
r
Do you think for a large project a sealed class/interface is more flexible, less error-prone, and easier to maintain than a property-based state?
h
Yes. What I do is define it like this
Copy code
sealed class OResponseWrapper<out T> {
    data class Success<out T>(val data: T) : OResponseWrapper<T>()

    data class Error(val message: String? = null, val cause: Throwable? = null) :
        OResponseWrapper<Nothing>()

    data object Loading : OResponseWrapper<Nothing>()
}
And, in this case I'll do separate handlings for Success and Error state and instead of handling Loading state, I'll show loader in
else
block of when statement. By doing this, suppose i added one more class later on as:
Copy code
sealed class OResponseWrapper<out T> {
    data class Success<out T>(val data: T) : OResponseWrapper<T>()

    data class Error(val message: String? = null, val cause: Throwable? = null) :
        OResponseWrapper<Nothing>()

    data object Loading : OResponseWrapper<Nothing>()

    data object LoadingMore : OResponseWrapper<Nothing>()
}
This
LoadingMore
is used for showing progress when I am doing pagination in a recycler view. So, I'll handle this LoadingMore explicitly on the intended places only.