这可能是我目前看的最舒服的Kotlin数据Handle类了

前言

毕竟是第一次在这上面写东西,感觉开头不写点什么东西不太好,不太严谨。那我就来个严谨的吧。在我们开发当中不可避免的会与数据打交道,数据可以来自network,local...因此很快就会想到一个模版:

kotlin 复制代码
class XxxRep {
    suspend fun getData(): Result<YourData>
 }
 
class XxxUseCase(
    private val xxRepImpl: XxxRep
) {
    operator fun invoke() {
        xxxRepImpl.getData()
        ///
    }
}

有木有那种感觉了.接下来我们就要针对结果的success和failure去进行处理就行了,现在我要讲的就是包装这个Result。

a. sealed interface

这里先看一下代码

kotlin 复制代码
    sealed class Result<T>(val data : T?= null, val message: String? = null) {
        data class Success<T>(val data: T?): Result<T>(data)
        data class Error<T>(val message: String? = null, val data: T? = null): Result<T>(data, message)
    }

是不是通用的密封类看起来觉得还行,但是我现在不用它了。理由无他,我不想写那么多的参数。开玩笑的,一方面有这理由,还有一方面就是我认为具体的message不应该是string直接在data层获取并一步步传递到domain层再到presentation层,我们应该包装成一种状态的形式用于表示error。大白话就是用个枚聚类表示error状态,然后定义些许个string。

csharp 复制代码
sealed interface Error  
  
typealias RootError = Error  
  
sealed interface Result<out D, out E : RootError> {  
    data class Success<out D, out E : RootError>(val data: D) : Result<D, E>  
    data class Error<out D, out E : RootError>(val error: E) : Result<D, E>  
}  
  

我来解释一下👀 首先我定义了一个顶层Error,这意味着我们后续所有模块中的Error都是它的弟弟,哦不,儿子。

kotlin 复制代码
sealed interface DataError: Error {  
    enum class NetWorkError : DataError {  
        NO_INTERNET,  
        TOO_MANY_REQUESTS,  
        UNEXPECTED_TOKEN,  
        PAYLOAD,  
        REQUEST_TIMEOUT  
    }  

    enum class LocalError: DataError {  
        SERIALIZATION,  
        UNKNOWN  
        }  
}

sealed interface XxxUseCaseError : Error {  
    enum class FinalError : XxxUseCaseError {  
        ABC_ERROR,  
        CHUNK_ERROR  
    }  
}

然后我用typealias取了个别名,这个没有啥特别含义啊,就是单纯命名以及泛型名称一样会报错罢了。 最后和之前的一样,定义了data,error并用out修饰,意思就是提前口头警告你小子这些个参数改不了,只能给爷乖乖读。

b. Data

核心已经结束了,剩下的就是怎么串联起来了,我们只要将上面的rep的改一下。

kotlin 复制代码
interface AuthRep {  
    suspend fun registerUser(name: String?): Result<User, DataError>  
}  
  
class NetAuthRepImpl: AuthRep {  
    override suspend fun registerUser(name: String?): Result<User, DataError> {  
        return Result.Error(DataError.NetWorkError.NO_INTERNET)  
    }  
}  
  
class LocalAuthRepImpl: AuthRep {  
    override suspend fun registerUser(name: String?): Result<User, DataError> {  
        return Result.Error(DataError.LocalError.SERIALIZATION)  
    }  
}  
  
data class User(  
    val id: Int,  
    val name: String,  
    val email: String  
)

剩下的大家懂得都懂了,我们只要在viewModel或者useCase中去使用when分别处理结果就行了。

scss 复制代码
class RegisterUserUseCase(  
    private val netAuthRepImpl: AuthRep = NetAuthRepImpl(),  
    private val localAuthRepImpl: AuthRep = LocalAuthRepImpl()  
) {  
  
suspend fun registerUser(name: String) {  
    when(val result = netAuthRepImpl.registerUser(name)) {  
    is Result.Error -> { handleNetWorkError(result.error) }  
    is Result.Success -> TODO()  
    } 
}  
  
private fun handleNetWorkError(error: DataError) {  
    when(error) {  
        DataError.LocalError.SERIALIZATION -> TODO()  
        DataError.LocalError.UNKNOWN -> TODO()  
        DataError.NetWorkError.NO_INTERNET -> TODO()  
        DataError.NetWorkError.TOO_MANY_REQUESTS -> TODO()  
        DataError.NetWorkError.UNEXPECTED_TOKEN -> TODO()  
        DataError.NetWorkError.PAYLOAD -> TODO()  
        DataError.NetWorkError.REQUEST_TIMEOUT -> TODO()  
    }  
}  
  

到这里好像一下子就明朗起来了✌️,结束!

塔塔开

实在想不出来取什么标题了,最近刚又补完进击的巨人,就鬼使神差了。到这里我们再做一个扩展,其实对于我们来说,前期的努力是为了后期的装杯,因此到这里还没完。可以看到我的useCase中只用了一个netAuthImpl的方法,其实在我们实际场景中我们基本避免不了网络获取数据,本地存储数据这一个单向流操作。因此我们又很容易写出这样的:

kotlin 复制代码
when(val result = netAuthRepImpl.registerUser(name)) {  
        is Result.Error -> { handleNetWorkError(result.error) }  
        is Result.Success -> {  
        localAuthRepImpl.registerUser(result.data.name)  
    }  
}
    

MD确实好像也没啥问题,也不错,淦,那要不结束了吧。怎么可能,我这个例子比较简单罢了。我想要的是一种简洁明了跟读手册一样啊くそやろ!

kotlin 复制代码
inline fun <D, E : RootError, R> Result<D, E>.andThen(block: D.() -> Result<R, E>): Result<R, E> {  
    return when (this) {  
        is Result.Error -> {  
            Result.Error(this.error)  
        }  

        is Result.Success -> {  
            block(this.data)  
        }  
    }  
}  
  
  
inline fun <D, E : RootError> Result<D, E>.onSuccess(action: (value: D) -> Unit): Result<D, E> {  
    if (this is Result.Success) {  
        action(this.data)  
    }  
    return this  
}  
  
inline fun <D, E : RootError> Result<D, E>.onFailure(action: (error: E) -> Unit): Result<D, E> {  
    if (this is Result.Error) {  
        action(this.error)  
    }  
    return this  
}

fun Result<*, DataError>.asUnitText() {  
if (this is Result.Error) {  
    when (this.error) {  
        DataError.LocalError.SERIALIZATION -> "Ooops, There is some error when serializing the data!"  
        DataError.LocalError.UNKNOWN -> TODO()  
        DataError.NetWorkError.NO_INTERNET -> TODO()  
        DataError.NetWorkError.TOO_MANY_REQUESTS -> TODO()  
        DataError.NetWorkError.UNEXPECTED_TOKEN -> TODO()  
        DataError.NetWorkError.PAYLOAD -> TODO()  
        DataError.NetWorkError.REQUEST_TIMEOUT -> TODO()  
    }  
    } else {  
        throw Exception()  
    }

我扩展了Result方法,很简单,简单的让我误以为自己很厉害了。

kotlin 复制代码
return netAuthRepImpl.registerUser(name).andThen {  
    localAuthRepImpl.registerUser(this.name)  
}.onSuccess {  
    // do works  
}.onFailure {  
    handleNetWorkError(it)  
}

简洁明了吧,over~😏

最后

其中可能涉及了一些架构术语,像domain,usecase诸如此类,其实这是来自整洁架构的定义。有兴趣的朋友可以了解一下,我简单介绍一下,核心就是将整个结构分为三部分,数据,操作,显示三个域,每个域互相隔离。真特么简单,这个介绍😄(我自己先吐槽一下)。

作为一个老看客了,距离上一次写技术博客还是疫情年上大学的时候,我也不知道为什么突然写了,想做就做了,可能人就是这样的生物吧。

少年时你听到人们说应该欣赏日落,但你忙于探索世界,不能静静地坐下来观赏。再后来,你抗拒本应该感觉得到的情感,斥之为庸俗。随着年龄的增长,你不再关心日落在别人眼中的是否庸俗。你用自己的眼睛去看它,内心充满感激和欣喜。

相关推荐
雨白5 小时前
深入理解 Kotlin 协程 (四):大道至简,于微末的挂起恢复中衍化万物
kotlin
jinanwuhuaguo13 小时前
OpenClaw 2026年4月升级大系深度解读剖析:从“架构重塑”到“信任内建”的范式跃迁
android·开发语言·人工智能·架构·kotlin·openclaw
我命由我1234515 小时前
Android Jetpack Compose - SearchBar(搜索栏)、Tab(标签页)、时间选择器、TooltipBox(工具提示)
android·java·java-ee·kotlin·android studio·android jetpack·android-studio
Lsk_Smion15 小时前
Hot100(开刷) 之 长度最小的数组--删除倒数第N个链表--层序遍历
java·数据结构·算法·kotlin
我命由我1234517 小时前
Android Jetpack Compose - 组件分类:布局组件、交互组件、文本组件
android·java·java-ee·kotlin·android studio·android jetpack·android-studio
Kapaseker18 小时前
让你的 App 成为 AI 的一环
android·kotlin
千码君20161 天前
kotlin:Jetpack Compose 给APP添加声音(点击音效/背景音乐)
android·开发语言·kotlin·音效·jetpack compose
Kapaseker2 天前
lazy 与 lateinit 到底有什么区别?
android·kotlin
雨白2 天前
深入理解 Kotlin 协程 (三):返璞归真,探寻协程基础设施的底层基石
kotlin
call me by ur name2 天前
ERNIE 5.0 Technical Report论文解读
android·开发语言·人工智能·机器学习·ai·kotlin