7

记Kotlin类型安全构建器的一次运用

 3 years ago
source link: https://mingdroid.github.io/2020/06/21/%E8%AE%B0Kotlin%E7%B1%BB%E5%9E%8B%E5%AE%89%E5%85%A8%E6%9E%84%E5%BB%BA%E5%99%A8%E7%9A%84%E4%B8%80%E6%AC%A1%E8%BF%90%E7%94%A8/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

记Kotlin类型安全构建器的一次运用

在android官方指导的相关应用框架中,用到一个Resource类来表示网络请求的状态与结果

1
2
3
4
5
6
7
8
9
// A generic class that contains data and status about loading this data.
sealed class Resource<T>(
val data: T? = null,
val message: String? = null
) {
class Success<T>(data: T) : Resource<T>(data)
class Loading<T>(data: T? = null) : Resource<T>(data)
class Error<T>(message: String, data: T? = null) : Resource<T>(data, message)
}

大多数情况下我们在activity里面是这样用的

1
2
3
4
5
6
7
8
9
10
11
12
private val testViewModel : TestViewModel by viewModels()

private fun getUserInfo(uid: String) {
testViewModel.userInfoData.observe(this, Observer {
when (it.status) {
Status.SUCCESS -> TODO()
Status.ERROR -> TODO()
Status.LOADING -> TODO()
}
})
testViewModel.setUserId(uid)
}

这样写多了感觉好烦,每次都是when(),有没有更爽的写法呢?比如这样?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private fun getUserInfo(uid: String) {
testViewModel.userInfoData.observe(this, Observer {
success {

}
error {

}
loading {

}
})
testViewModel.setUserId(uid)
}

当我只需要处理success的时候,我可以不写error/loading情况。

kotlin的类型安全构建器可以做到,我们先看下官方的示例

1
2
3
4
5
6
7
8
9
10
11
12
13
class HTML {
fun body() { …… }
}

fun html(init: HTML.() -> Unit): HTML {
val html = HTML() // 创建接收者对象
html.init() // 将该接收者对象传给该 lambda
return html
}

html { // 带接收者的 lambda 由此开始
body() // 调用该接收者对象的一个方法
}

先分析下,我们需要的是一个实现了Observer接口的对象。

所以我们先定义一个类来实现Observer接口

1
2
3
4
5
6
7
8
9
class ResourceObserver<T: Any> : Observer<Resource<T>> {
override fun onChanged(t: Resource<T>) {
when(t) {
is Resource.Success -> TODO()
is Resource.Error -> TODO()
is Resource.Loading -> TODO()
}
}
}

实现一个顶层函数,返回一个ResourceObserver对象

1
2
3
4
5
fun <T: Any> resourceObserver(init: ResourceObserver<T>.() -> Unit): ResourceObserver<T> {
val observer = ResourceObserver<T>()
observer.init()
return observer
}

调用该函数即可得到ResourceObserver对象

1
2
3
resourceObserver {
//在此处可以调用对象内的成员函数
}

所以我的实现是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class ResourceObserver<T: Any> : Observer<Resource<T>> {
private var success: (Resource.Success<T>.() -> Unit)? = null
private var error: (Resource.Error.() -> Unit)? = null
private var loading: (Resource.Loading<T>.() -> Unit)? = null

fun success(s: (Resource.Success<T>.() -> Unit)) {
success = s
}

fun error(e: Resource.Error.() -> Unit) {
error = e
}

fun loading(l: Resource.Loading<T>.() -> Unit) {
loading = l
}

override fun onChanged(t: Resource<T>) {
when(t) {
is Resource.Success -> success?.invoke(t)
is Resource.Error -> error?.invoke(t)
is Resource.Loading -> loading?.invoke(t)
}
}
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK