Skip to content

Instantly share code, notes, and snippets.

@dingbuoyi
Last active October 19, 2021 06:34
Show Gist options
  • Save dingbuoyi/528ea9375a9ff4ebc2a5c15a151466b3 to your computer and use it in GitHub Desktop.
Save dingbuoyi/528ea9375a9ff4ebc2a5c15a151466b3 to your computer and use it in GitHub Desktop.
四种不同的方法封装带网络状态的LiveData
// 实现一
# 状态类
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