安卓Jetpack进阶——map与switchMap(二)

911 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第21天,点击查看活动详情,希望大家多多支持,帮忙点个赞,谢谢!

前言

第一篇我们将Transformations的map()方法拿来救场,为我们的User类保护了用户隐私。这篇我们就来看看switchMap(),这个方法使用场景非常固定,但可能比map()方法更加常用。

正篇

首先,让我们看看LiveData不在ViewModel中创建的情景,我们新建一个Repository单例类:

object Repository {

    fun getUser(userId : String) : LiveData<User> {
        val liveData = MutableLiveData<User>()
        liveData .value = User(userId, userId, 0)
        return liveData
    }
}

我们在此类中写了一个getUser()方法,该方法可以接受一个userId参数,每次将传入的userId当作用户姓名去创建一个新的User对象,而且需要注意的是,getUser()方法返回的是一个包含User数据的LiveData对象,且其每次调用都会获取LiveData对象。

接着我们在ViewModel中也定义一个getUser()方法,然后用它去调用Repository的getUser()方法从而获取LiveData对象,至此,我们构建了一个不在ViewModel中创建LiveData的情景,如果按之前的写法来:

class MainViewModel(countReserved: Int) : ViewModel() {
         ...
     fun getUser(userId : String) : LiveData<User> {
         return Repository.getUser(userId)
      }
     
}

MainActivity中:

viewModel.getUser(userId).observe(this) { user ->
}

上面的写法显然是行不通的,由于每次调用getUser方法都返回了新的LiveData实例,而MainActivity中观察的都是旧的实例,于是无法正确观测的数据变化,所以导致这种情况下LiveData无法观察。

于是,为了应对这种情况,我们就可以使用switchMap()方法,它的使用场景正是在如果ViewModel中的某个LiveData对象不是自己创建的而是调用其他方法获取的,那我们就可以用该方法去将LiveData对象转换成另一个可观察的LiveData对象:

class MainViewModel(countReserved: Int) : ViewModel() {

    ...

    private val userIdLiveData = MutableLiveData<String>()
    
    val user: LiveData<User> = Transformations.switchMap(userIdLiveData) { userId ->
        Repository.getUser(userId)
    }
    
    fun getUser(userId : String) {
        userIdLiveData.value = userId
    }
}

与map()方法类似,不过第二个参数不同,我们必须在这个转换函数中返回一个LiveData对象,因为switchMap()方法的工作原理即将转换函数中返回的LiveData对象转换成另一个可观察的LiveData对象。 接下来再将xml布局与MainActivity对应调整: activity.xml再加一个按钮:

<Button
    android:id="@+id/getUserBtn"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:text="Get User"/>

MainActivity中添加按钮的事件与对应LiveData观察:

val getUserBtn : Button = findViewById(R.id.getUserBtn)
getUserBtn.setOnClickListener {
    val userId = (0..10000).random().toString()
    viewModel.getUser(userId)
}
viewModel.user.observe(this, Observer { user ->
    infoText.text = user.firstName
})

最后运行一下,我们一直点击“Get User”按钮,可以看到数据在随机变化,如下:

untitled.gif

结语

到目前为止,我们已经把关于Jetpack组件LiveData中的相关部分说的差不多了,后面还有Room等,等待有时间后会继续更新。