【问题标题】:Starting an fragment within a view model在视图模型中启动片段
【发布时间】:2020-05-18 18:45:57
【问题描述】:

我正在尝试修改我的学习项目以使用 MVVM 和数据绑定。

项目在这里:https://github.com/Sophon/CriminalIntent/tree/dev

在返工之前,该应用的行为如下:

  • MainActivity 承载一个CrimeListFragment,它是Crimes
  • RecyclerView
  • CrimeHolder 实现 View.OnClickListeneronClick() 使用回调函数与 Crimeid 被点击
  • MainActivity 实现回调函数并使用supportFragmentManager 启动特定的(用id 标识)CrimeDetailFragment
  • 这种行为可以在 Master 分支中看到。

现在,在返工时,这是我目前所拥有的:

  • list_item.xml 使用数据绑定
  • CrimeViewModel 有一个属性 crime: Crime
  • 我为CrimeListFragmentonCreateView() 中的绑定充气
  • CrimeHolder 类有 init { binding.viewModel = CrimeViewModel() }
  • CrimeHolder 也有bind(crime: Crime),我将crime 分配给viewModelcrime
  • CrimeListAdapter 类自解释
  • 在链接的分支 dev 中可以看到此行为

RecyclerView 中的每个犯罪都是可点击的,这意味着list_item.xml 将有android:onClick="@{() -> viewModel.onCrimeClicked()}"CrimeViewModel 将有一个函数onCrimeClicked()

我的问题是:如何在符合 MVVM 架构的同时从 viewmodel 的 onClicked() 开始一个新片段 (CrimeDetailFragment)?

我可以像以前一样在 Holder 中简单地实现 View.OnClickListener,但使用 MVVM 我应该避免 View 中的逻辑 (CrimeListFragment就我而言)。

额外的问题 - 我应该实施哪些其他更改才能获得更多 MVVM?

【问题讨论】:

  • MVVM 架构的重点是将 ViewModel 的关注点与实际视图本身分开,因此从视图模型中打开片段将是一个糟糕的选择。相反,当在回收站视图中单击犯罪时,您应该在视图模型中更改所选犯罪的值,例如 viewModel.setSelectedCrime(selectedCrime)。然后,您的 MainActivity 应该观察您的 viewModel,并且当 selectedCrime 已更改时,它应该启动 CrimeDetailFragment
  • @RyanSaffer 好的,所以我在 viewModel 类中设置了 LiveData 属性。现在我不太清楚我应该如何开始在 MainActivity 中观察。 MainActivity 如何获得list_item_crime.xml 使用的binding.viewModel
  • 我也不太清楚你在说哪个视图模型。每个 RecyclerV 项目都有自己的视图模型,所以我无法观察每个项目。因此,如果您的意思是CrimeListViewModel,那么我不清楚片段如何知道选择了哪个项目。

标签: android android-fragments kotlin mvvm data-binding


【解决方案1】:

IMO,我会在 Activity 或 Fragment 中创建一个 lambda 块,然后将一个 lambda 块传递给适配器,例如:

private val onCrimeClicked: (Crime) -> Unit = {
    // This will be triggered later
}
private val crimeListAdapter = CrimeListAdapter(onCrimeClicked)

在适配器内部,您将相同的 lambda 块传递给 CrimeHolder 的构造函数,您将在 onCreateViewHolder() 中创建新的 CrimeHolder。

然后,您的 CrimeHolder 类可能如下所示:

class CrimeHolder(private val onCrimeClicked: (Crime) -> Unit = {}){

    fun bind(crime : Crime){
        list.setOnClickListener{
            onCrimeClicked(crime)
        }
    }
}

看看这是否适合你的需要!

PS:这样你就无法打破 MVVM 规则。

【讨论】:

  • 所以如果我理解正确的话,在 Adapter 类中我创建一个使用回调的函数属性,然后我创建一个以该函数属性作为参数的 Holder。 Holder 然后创建一个 ViewModel 实例,将该函数属性也作为参数,最后 ViewModel 的 onClick() 使用该函数。正确的? gist.github.com/Sophon/3efe0afb48bdd4d1c525e64bd22da5f7
  • 只是确保我正确理解了您,因为尽管代码似乎对我有用,但也许我没有正确理解您并且我的代码可能违反 MVVM 准则。
猜你喜欢
  • 2021-02-11
  • 2013-11-04
  • 2018-02-26
  • 1970-01-01
  • 2021-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多