Last active
October 19, 2021 06:34
-
-
Save dingbuoyi/528ea9375a9ff4ebc2a5c15a151466b3 to your computer and use it in GitHub Desktop.
四种不同的方法封装带网络状态的LiveData
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 实现一 | |
# 状态类 | |
sealed class Resource<T>( | |
val data: T? = null, | |
val errorCode: Int? = null | |
) { | |
class Success<T>(data: T) : Resource<T>(data) | |
class Loading<T>(data: T? = null) : Resource<T>(data) | |
class DataError<T>(errorCode: Int?) : Resource<T>(null, errorCode) | |
override fun toString(): String { | |
return when (this) { | |
is Success<*> -> "Success[data=$data]" | |
is DataError -> "Error[exception=$errorCode]" | |
is Loading<T> -> "Loading" | |
} | |
} | |
} | |
# 定义在ViewModel中的LiveData | |
private val loginLiveDataPrivate = MutableLiveData<Resource<LoginResponse>>() | |
val loginLiveData: LiveData<Resource<LoginResponse>> get() = loginLiveDataPrivate | |
# 在Activity中监听 | |
loginViewModel.loginLiveData.observe(this) { status -> | |
when (status) { | |
is Resource.Loading -> binding.loaderView.toVisible() | |
is Resource.Success -> status.data?.let { | |
binding.loaderView.toGone() | |
navigateToMainScreen() | |
} | |
is Resource.DataError -> { | |
binding.loaderView.toGone() | |
status.errorCode?.let { loginViewModel.showToastMessage(it) } | |
} | |
} | |
} | |
// 实现二 | |
# 添加typealias和扩展方法 | |
typealias StatefulLiveData<T> = LiveData<Resource<T>> | |
typealias StatefulMutableLiveData<T> = MutableLiveData<Resource<T>> | |
@MainThread | |
inline fun <T> StatefulLiveData<T>.observeState( | |
owner: LifecycleOwner, | |
crossinline onLoading: () -> Unit = {}, | |
crossinline onSuccess: (T?) -> Unit = {}, | |
crossinline onError: (Int?) -> Unit = {} | |
) { | |
observe(owner, Observer { state -> | |
when (state) { | |
is Resource.Loading -> onLoading.invoke() | |
is Resource.Success -> onSuccess(state.data) | |
is Resource.DataError -> onError(state.errorCode) | |
} | |
} | |
} | |
# 在Activity中监听 | |
loginViewModel.loginLiveData.observeState(this, | |
onLoading = { | |
binding.loaderView.toVisible() | |
}, | |
onSuccess = { data -> | |
binding.loaderView.toGone() | |
data?.let { | |
navigateToMainScreen() | |
} | |
}, | |
onError = { errorCode -> | |
binding.loaderView.toGone() | |
errorCode?.let { loginViewModel.showToastMessage(it) } | |
} | |
) | |
// 方法三 | |
# 在状态类中增加inline方法 | |
sealed class Resource<T>( ... // 省略 | |
inline fun <reified T> Resource<T>.onLoading(onLoading: () -> Unit) { | |
if (this is Resource.Loading) { | |
onLoading() | |
} | |
} | |
inline fun <reified T> Resource<T>.onSuccess(onSuccess: (T?) -> Unit) { | |
if (this is Resource.Success) { | |
onSuccess(data) | |
} | |
} | |
inline fun <reified T> Resource<T>.onError(onError: (Int?) -> Unit) { | |
if (this is Resource.DataError) { | |
onError(errorCode) | |
} | |
} | |
# 在Activity中监听 | |
loginViewModel.loginLiveData.observe(this) { status -> | |
status.onLoading { | |
binding.loaderView.toVisible() | |
} | |
status.onSuccess { data -> | |
binding.loaderView.toGone() | |
data?.let { | |
navigateToMainScreen() | |
} | |
} | |
status.onError { errorCode -> | |
binding.loaderView.toGone() | |
errorCode?.let { loginViewModel.showToastMessage(it) } | |
} | |
} | |
// 方法四 Kotlin DSL风格 | |
abstract class IStateObserver<T> : Observer<Resource<T>> { | |
override fun onChanged(resource: Resource<T>) { | |
when (resource) { | |
is Resource.Loading -> onLoading() | |
is Resource.Success -> onSuccess(resource.data) | |
is Resource.DataError -> onError(resource.errorCode) | |
} | |
} | |
abstract fun onLoading() | |
abstract fun onSuccess(data: T?) | |
abstract fun onError(errorCode: Int?) | |
} | |
class StateLiveData<T> : MutableLiveData<Resource<T>>() { | |
fun observeState(owner: LifecycleOwner, function: ListenerBuilder.() -> Unit) { | |
val listener: StateLiveData<T>.ListenerBuilder = ListenerBuilder().also(function) | |
//下面这种写法等同于上面also的写法 | |
//val listener: StateLiveData<T>.ListenerBuilder = ListenerBuilder() | |
//listener.function() | |
val value = object : IStateObserver<T>() { | |
override fun onLoading() { | |
listener.mLoadingListenerAction?.invoke() | |
} | |
override fun onSuccess(data: T?) { | |
listener.mSuccessListenerAction?.invoke(data) | |
} | |
override fun onError(errorCode: Int?) { | |
listener.mErrorListenerAction?.invoke(errorCode) | |
} | |
} | |
super.observe(owner, value) | |
} | |
inner class ListenerBuilder { | |
internal var mSuccessListenerAction: ((T?) -> Unit)? = null | |
internal var mErrorListenerAction: ((Int?) -> Unit)? = null | |
internal var mLoadingListenerAction: (() -> Unit)? = null | |
fun onLoading(action: () -> Unit) { | |
mLoadingListenerAction = action | |
} | |
fun onSuccess(action: (T?) -> Unit) { | |
mSuccessListenerAction = action | |
} | |
fun onError(action: (Int?) -> Unit) { | |
mErrorListenerAction = action | |
} | |
} | |
} | |
# 在Activity中监听 | |
loginViewModel.loginLiveData.observeState(this) { | |
onLoading { | |
binding.loaderView.toVisible() | |
} | |
onSuccess { data -> | |
binding.loaderView.toGone() | |
data?.let { | |
navigateToMainScreen() | |
} | |
} | |
onError { errorCode -> | |
binding.loaderView.toGone() | |
errorCode?.let { loginViewModel.showToastMessage(it) } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment