【问题标题】:Android, how to observe LiveData from within the same ViewModelAndroid,如何从同一个 ViewModel 中观察 LiveData
【发布时间】:2021-08-06 04:14:35
【问题描述】:

在 LiveData 和 MVVM 架构方面,我完全是个新手。我试图弄清楚如何观察 ViewModel 中的 LiveData 以根据它是否为空来更新另一个变量。

我正在从我的 Room 数据库中获取 LiveData:

class MealsViewModel @Inject constructor(
    private val mealDao : MealDao
) : ViewModel() {

    ...

    private val currentDay: MutableLiveData<Date> = MutableLiveData(Date())
    val meals = Transformations.switchMap(currentDay){ date -> mealDao.getMeals(date).asLiveData() }

我希望 ViewModel 中的另一个变量 private val empty: Boolean 在列表返回空(null)时进行更新。这将用于将 Fragment 中的 ImageView 从 Visible.GONE 更新为 Visible.VISIBLE。

如何同步检查val meals是否为空?

我已经阅读并看到有人说要使用observeForever,但架构指南明确建议不要在 ViewModels 中使用任何观察者。

我可能会在 Fragment 中观察 LiveData,但这需要 Fragment 中的业务逻辑,即:

viewModel.meals.observe(viewLifecycleOwner) {

    if meals.value.isEmpty() imageView.visibility = View.VISIBLE else imageView.visibility = View.GONE
}

而且我想让 Fragment 尽可能“愚蠢”,所以我更愿意在 ViewModel 中使用这种逻辑。这可能吗?

【问题讨论】:

    标签: android mvvm android-livedata


    【解决方案1】:

    您可以检查实时数据 meal 以查看它是否为空或 null,然后使用您的实时数据 empty 触发,如下所示:

    在视图模型中,您创建一个 livedata isEmptyMeals。当meals 值更改时,此实时数据变量将始终触发,并将检查您的meals 值是空还是空。

    MealsViewModel.kt

    class MealsViewModel @Inject constructor(
        private val mealDao : MealDao
    ) : ViewModel() {
    
        ...
    
        private val currentDay: MutableLiveData<Date> = MutableLiveData(Date())
        val meals = Transformations.switchMap(currentDay){ date -> mealDao.getMeals(date).asLiveData() }
        
        val isEmptyMeals = meals.map {
            it.isNullOrEmpty()
        }
    }
    
    

    并且在片段中,您将收听观察 livedata isEmptyMeals 并执行隐藏或显示您想要的图像视图的逻辑。

    Fragment.kt

    viewModel.isEmptyMeals.observe(viewLifecycleOwner) {
        imageView.visibility = if (it) View.VISIBLE else View.GONE
    }
    

    【讨论】:

    • 我将 if (it.isNullOrEmpty()) View.VISIBLE else View.GONE 移动到 ViewModel 中的 .map 中,它运行良好。使用 imageView.visibility = it 之后,Fragment 变得又好又简单。谢谢!
    【解决方案2】:

    我不确切知道您的代码是如何设置的,但您可以执行以下操作

    将变量添加到 ViewModel

    val empty = MutableLiveData<Boolean>()
    

    meals观察者 viewModel.meals.observe(viewLifecycleOwner) {

    viewModel.empty,postValue(meals.value.isEmpty())
    

    然后从empty观察

    使用 MediatorLiveData

    在您的 ViewModel 类中,创建

    val empty = MediatorLiveData<Boolean>()
    

    然后

    empty.addSource(meals) {
        empty.value = it.isEmpty()
    }
    

    【讨论】:

    • 有趣。所以你建议我应该从片段中观察 ViewModel 中的 LiveData 并更新 val 为空?这会违反 MVVM 的原则吗?
    • 在您的情况下,这样做更容易。如果您正确理解基础知识,也可以使用MediatorLiveData。 MediatorLiveData 是建议的选项。 developer.android.com/reference/androidx/lifecycle/…
    • 我还用MediatorLiveData更新了答案
    • 使用MediatorLiveData也是一种方式。但当您需要收听多个实时数据源时,通常会使用它。因为在这里他想检查 livedata meals 是 null 还是空。所以我们将使用 Transformation LiveData 扩展 map。扩展map 本质上是从MediatorLiveData 生成的。一般来说,如果您需要监听多个 livedata 源,请使用 MediatorLiveData,但如果您只监听 1 个 livedata 源更改,则应使用 Transformation map 扩展。
    • 是的,你是对的,这让我忽略了。但这将与我的第一个实现相同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多