28

简易MVVM网络请求框架(一些解析)

 3 years ago
source link: https://mingdroid.github.io/2020/04/10/%E7%AE%80%E6%98%93MVVM%E7%BD%91%E7%BB%9C%E8%AF%B7%E6%B1%82%E6%A1%86%E6%9E%B6%EF%BC%88%E4%B8%80%E4%BA%9B%E8%A7%A3%E6%9E%90%EF%BC%89/
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.

ViewModel实现

1
2
3
4
5
6
7
8
9
10
11
class TestViewModel : ViewModel() {
private val testRepo = TestRepo(viewModelScope.coroutineContext)
private val _uidData = MutableLiveData<String>()
val userInfoData = _uidData.switchMap {
testRepo.getUserInfo(it)
}

fun setUserId(uid: String) {
_uidData.value = uid
}
}

代码量很少,涉及到哪些知识点呢?

  1. switchMap

    其实就是Transformations.switchMap(),简述就是_uidData.value有了更新(不管值有没有发生改变),则会通知到switchMap执行其后面的代码块testRepo.getUserInfo(it)

    1
    2
    3
    4
    5
    6
    //信息量更多的代码
    val userInfoData: LiveData<Resource<UserInfo>> = _uidData.switchMap {
    uid ->
    val result: LiveDdata<Resource<UserInfo>> = testRepo.getUserInfo(uid)
    return result
    }

    userInfoData其实是一个MediatorLiveData

  2. MediatorLiveData

    可以同时监听很多个LiveData源,查看MediatorLiveData源码知道在onActive/onInactive会添加监听/移除监听各个LiveData源~

  3. viewModelScope

    [viewModelScope] tied to this [ViewModel].
    This scope will be canceled when ViewModel will be cleared, i.e [ViewModel.onCleared] is called

尽管ViewModel里面没看到清理代码,实际上是有的,当activity.onDestroy后,ViewModel.clear会被调用,viewModelScope.cancel也会被调用,viewModelScope.cancel会导致正在请求的API被取消的。所以activity关闭后,正在请求的API也会被取消,这很好。当然如果你不想API被取消,那你就不要使用viewModelScope。

我们在Repo里面开启的协程,使用的是viewModelScope.coroutineContext,当viewModelScope被取消后,其子协程同样会被取消的。所以我们向TestRepo传递了viewModelScope.coroutineContext

private val testRepo = TestRepo(viewModelScope.coroutineContext)

Repo的实现

主要需要理解LiveDataScope,看下liveData的源码

1
2
3
4
5
fun <T> liveData(
context: CoroutineContext = EmptyCoroutineContext,
timeoutInMs: Long = DEFAULT_TIMEOUT,
@BuilderInference block: suspend LiveDataScope<T>.() -> Unit
): LiveData<T> = CoroutineLiveData(context, timeoutInMs, block)

第一个参数是协程的上下文,我们要与ViewModel同步,所以用的是viewModelScope.coroutineContext

第二个参数是超时时间,liveData会返回CoroutineLiveData,当CoroutineLiveData.hasActiveObservers == false时,即开始倒计时(当然如果block代码已执行完,那就不会开启倒计时了),超时后会取消第三个参数block代码块的执行(如果没执行完)。实际情况来说就是block执行的是网络请求,那么在Activity.onStop后,开始倒计时,倒计时到达后如果block没执行完,则会取消其执行,然后在Activity.onStart后,block代码块会重新执行。但是如果在倒计时前block代码块已执行完,将不会再重新执行。

要说明一下,这里的取消执行并不是因为viewModelScope.cancel被调用了,而是因为CoroutineLiveData的onInactivie被调用了,进而发生的取消

我们再次回到ViewModel的实现

fun setUserId(uid: String)

如果连续多次调用这个函数会发生什么呢?调用一次就会做一次网络请求,如果在下次调用前网络返回了数据,那很正常的一次请求。但是如果网络没返回数据,而再次调用了该函数,那么前一次的网络请求会被取消,是立刻取消吗?这个要看liveDatatimeoutInMs超时参数值,如果你设置为0,那就是立刻取消的。默认是5000ms倒计时,即使倒计时到达前返回了数据,也不会再传递给userInfoData了。。这个看下switchMap的源码即可理解


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK