记Kotlin类型安全构建器的一次运用
在android官方指导的相关应用框架中,用到一个Resource 类来表示网络请求的状态与结果
1 2 3 4 5 6 7 8 9 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 () return html } html { 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 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) } } }