如何以及在哪里使用 Transformations.switchMap?

How and where to use Transformations.switchMap?

最近 Android 由 Google 发布的架构组件库中,我们在 Transformations class 中有两个静态函数。虽然 map 函数简单易懂,但我发现很难正确理解 switchMap 函数。

可以找到switchMap的官方文档here

有人可以通过实际示例解释如何以及在何处使用 switchMap 函数吗?

map()函数中

LiveData userLiveData = ...;
LiveData userName = Transformations.map(userLiveData, user -> {
     return user.firstName + " " + user.lastName; // Returns String
});

每当 userLiveData 的值发生变化时,userName 也会更新。请注意,我们正在返回 String

switchMap()函数中:

MutableLiveData userIdLiveData = ...;
LiveData userLiveData = Transformations.switchMap(userIdLiveData, id ->
    repository.getUserById(id)); // Returns LiveData

void setUserId(String userId) {
     this.userIdLiveData.setValue(userId);
}

每次userIdLiveData的值改变时,repository.getUserById(id)就会被调用,就像map函数一样。但是repository.getUserById(id)returns一个LiveData。因此,每当 repository.getUserById(id) 返回的 LiveData 的值发生变化时, userLiveData 的值也会发生变化。所以 userLiveData 的值将取决于 userIdLiveData 的变化和 repository.getUserById(id).

的值的变化

switchMap() 的实际示例:假设您有一个用户个人资料,其中包含一个关注按钮和一个设置另一个个人资料信息的下一个个人资料按钮。下一个配置文件按钮将使用另一个 ID 调用 setUserId(),因此 userLiveData 将更改并且 UI 将更改。关注按钮将调用 DAO 为该用户再添加一个关注者,因此该用户将拥有 301 个关注者而不是 300 个。userLiveData 将获得来自存储库的更新,该更新来自 DAO。

将我的 2 美分加到@DamiaFuentes 的回答中。

MutableLiveData userIdLiveData = ...;
LiveData userLiveData = Transformations.switchMap(userIdLiveData, id ->
repository.getUserById(id)); // Returns LiveData

void setUserId(String userId) {
     this.userIdLiveData.setValue(userId);
}

Transformations.switchMap 方法只会在您至少有一个 userLiveData

观察者时被调用

对于那些想要对下面给出的@DamiaFuentes switchmap() 函数示例进行更多解释的人:

 MutableLiveData userIdLiveData = ...;
 LiveData userLiveData = Transformations.switchMap(userIdLiveData, id ->
     repository.getUserById(id));

 void setUserId(String userId) {
      this.userIdLiveData.setValue(userId);
 }

在存储库包含User(1, "Jane")和User(2, "John")的场景下,当userIdLiveData值设置为“1”时,switchMap会调用getUser (1),这将 return 一个包含值 User(1, "Jane") 的 LiveData。所以现在,userLiveData 将发出 User(1, "Jane")。当存储库中的用户更新为 User(1, "Sarah") 时,userLiveData 会自动收到通知并发出 User(1, "Sarah").

当调用 setUserId 方法并设置 userId = "2" 时,userIdLiveData 的值发生变化并自动触发从存储库中获取 ID 为 "2" 的用户的请求。因此,userLiveData 发出 User(2, "John")。由 repository.getUserById(1) 编辑的 LiveData return 作为来源被删除。

从这个例子中,我们可以了解到 userIdLiveData 是触发器,由 repository.getUserById 编辑的 LiveData return 是 "backing" LiveData。

更多参考,查看:https://developer.android.com/reference/android/arch/lifecycle/Transformations

传递给switchMap的函数returnsLiveData。当您的存储库本身 returns LiveData.

时使用它

还有一点要考虑选择 switchMap 还是 map,你必须记住 map 总是将返回值包裹在 LiveData 周围,例如

fun getUser(id: Int): User 
...
val userId = MutableLiveData(1)
val user = userId.map { // LiveData<User>
   repository.getUser(it)
}

您可能会考虑使用 map 如果 repository.getUser(it) returns 一个简单的 User 对象而不是 LiveData 这样用户类型就变成了 LiveData<User>.

如果repository.getUser(it) returns a LiveData<User> 那么最好使用switchMap

fun getUser(id: Int): LiveData<User>
...
val userId = MutableLiveData(1)
val user = userId.switchMap { // LiveData<User>
   repository.getUser(it)
}

user 类型为 LiveData<User>

还有一点需要理解。 有人可能会想,因为我们总是在 switchMap() 中 return LiveData 的新值(新引用),所以我们如何在观察者只设置一次的情况下观察实际值? 重点是 Transformations.switchMap 的 returned 值是 MediatorLiveData,它将新的 LiveData 引用添加为新源(并停用其他源)。