簡介

程式碼範例

基本元件

Error.kt

interface Error

這是一個基礎的介面,方便做為其錯誤的擴充基礎

DataError.kt

sealed interface DataError: Error {

    enum class Network: DataError {
        REQUEST_TIMEOUT,
        UNAUTHORIZED,
        CONFLICT,
        TOO_MANY_REQUESTS,
        NO_INTERNET,
        PAYLOAD_TOO_LARGE,
        SERVER_ERROR,
        SERIALIZATION,
        UNKNOWN
    }

    enum class Local: DataError {
        DISK_FULL
    }
}

這裏以網路 API 常見的錯誤為例

Result.kt

sealed interface Result<out D, out E: Error> {
    data class Success<out D>(val data: D) : Result<D, Nothing>

    data class Error<out E: app.kirin.util.Error>(val error: E) : Result<Nothing, E>
}

inline fun <T, E: Error, R> Result<T, E>.map(map: (T) -> R): Result<R,E> {
    return when(this) {
        is Result.Error -> Result.Error(error)
        is Result.Success -> Result.Success(map(data))
    }
}

fun <T, E: Error> Result<T, E>.asEmptyResult(): EmptyResult<E> {
    return map { }
}

typealias  EmptyResult<E> = Result<Unit, E>

實際使用範例 – 1

LoginViewModel.kt

class LoginViewModel(
    private val authRepository: AuthRepository
): ViewModel() {

    ...

    private fun login() {
        viewModelScope.launch {
            ...
            
            val result = authRepository.login(
                email = state.email.text.toString().trim(),
                password = state.password.text.toString()
            )

            when(result) {
                is Result.Error -> {
                    if(result.error == DataError.Network.UNAUTHORIZED) {
                        // 登入不成功,可能是帳密不符
                    } else {
                        // 登入不成功: 其他原因
                    }
                }
                is Result.Success -> {
                    // 登入成功
                }
            }
        }
    }

}

實際使用範例 – 2

enum class PasswordValidationError: Error {
    TOO_SHORT,
    MISSION_ONE_DIGIT
}

fun validatePassword(password: String): Result<Unit, PasswordValidationError> {
    // TODO: validation login here

    // if error
    return Result.Error(PasswordValidationError.MISSION_ONE_DIGIT)
}

fun handleError(result: Result<Unit, PasswordValidationError>) {
    when(result) {
        is Result.Error -> {
            when(result.error) {
                PasswordValidationError.TOO_SHORT -> TODO()
                PasswordValidationError.MISSION_ONE_DIGIT -> TODO()
            }
        }
        is Result.Success -> {
            // TODO: this is a valid password
        }
    }
}

參考資料

This Is My FAVORITE Error Handling Class – by Philipp

How to handle network errors with Ktor

Last modified: 2025 年 9 月 30 日

Author

Comments

Write a Reply or Comment

Your email address will not be published.