当前位置: 首页 > 知识库问答 >
问题:

我应该如何在两个片段中使用ViewModel?

王才英
2023-03-14

我有一个包含一个活动和两个片段的应用程序,在第一个片段中,我应该能够将数据插入数据库,在第二个片段中,我应该能够在一个RecyclerView中看到添加的项目。

所以我已经创建了数据库、我的RecyclerView适配器和ViewModel,

我是否应该在活动中初始化ViewModel,并以某种方式从片段中调用它来使用insert?

我是否应该在两个片段中初始化viewmodel两次?

我的代码如下所示:

class MainActivity : AppCompatActivity() {
     private val articoliViewModel: ArticoliViewModel by viewModels {
        ArticoliViewModelFactory((application as ArticoliApplication).repository)
    }
}
class FirstFragment : Fragment() {
    private val articoliViewModel: ArticoliViewModel by activityViewModels()
    private fun addArticolo(barcode: String, qta: Int) { // function which add should add items on click
      // here i should be able to do something like this

        articoliViewModel.insert(Articolo(barcode, qta))
    }
}
class SecondFragment : Fragment() {    
    private lateinit var recyclerView: RecyclerView
    private val articoliViewModel: ArticoliViewModel by activityViewModels()
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        recyclerView = view.findViewById(R.id.recyclerView)
        val adapter = ArticoliListAdapter()
        recyclerView.adapter = adapter
        recyclerView.layoutManager = LinearLayoutManager(activity)
        // HERE I SHOULD BE ABLE DO THIS   
        articoliViewModel.allWords.observe(viewLifecycleOwner) { articolo->
            articolo.let { adapter.submitList(it) }
        }

    } 
}

编辑:

我的ViewModel如下所示:

class ArticoliViewModel(private val repository: ArticoliRepository): ViewModel() {
    val articoli: LiveData<List<Articolo>> = repository.articoli.asLiveData()

    fun insert(articolo: Articolo) = viewModelScope.launch {
        repository.insert(articolo)
    }
}

class ArticoliViewModelFactory(private val repository: ArticoliRepository): ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(ArticoliViewModel::class.java)) {
            @Suppress("UNCHECKED_CAST")
            return ArticoliViewModel(repository) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }

}

共有1个答案

武晨
2023-03-14

多个片段是否应该共享一个ViewModel取决于它们是否显示相同的数据。如果它们显示相同的数据,我认为共享一个ViewModel通常是有意义的,这样当您在它们之间切换时就不必从存储库中提取数据,这样转换就更快了。如果它们中的任何一个也有大量的唯一数据,您可以考虑将这些数据分解到一个单独的ViewModel,这样它就不会在不需要占用内存的情况下占用内存。

假设您使用的是一个共享的ViewModel,您可以使用至少两种不同的方法中的一种,这取决于您更喜欢的代码样式。在封装和代码重复之间有一个小的权衡,尽管它并不是真正的封装,因为它们查看的是同一个实例。所以就我个人而言,我更喜欢第二种做法。

  1. 每个ViewModel直接创建ViewModel。如果您使用by activityViewModels(),那么ViewModel的作用域将被限定为活动,因此它们都将接收同一个实例。但是由于您的ViewModel需要一个自定义工厂,您必须在两个片段中都指定它,因此有一点代码重复:
// In each Fragment:
private val articoliViewModel: ArticoliViewModel by activityViewModels {
    ArticoliViewModelFactory((application as ArticoliApplication).repository)
}
// In Activity: The same view model code you already showed in your Activity, but not private

// In Fragments:
private val articoliViewModel: ArticoliViewModel
    get() = (activity as MainActivity).articoliViewModel

或者为了避免代码重复,您可以为片段创建一个扩展属性,这样它们就不必具有代码重复:

val Fragment.articoliViewModel: ArticoliViewModel
    get() = (activity as MainActivity).articoliViewModel
 类似资料:
  • 问题内容: 更确切地说,似乎我可以做这三件事中的任何一件。它们之间有什么区别吗?哪个最好,为什么? 问题答案: 1)是零切片。 2)和3)是长度为零,容量为零的非零切片。 操场上的例子 没有一个选项分配内存。 所有这些选项通常在Go代码中使用。 因为,并与零切片,1)的工作通常可以互换2)和3)中使用。

  • 问题内容: 我不太清楚当我这样说时会做什么: 我可以稍微了解使用它的原因,因为它不浏览整个数据库表以更新字段,而是仅更新新添加的记录。如我错了请纠正我。 所以我想做的是使用这样创建索引: 一旦执行此操作,文档就根本不会上传到索引。我要去哪里错了? 任何帮助,不胜感激。 问题答案: 如果您的表中有一个时间戳列(例如),则最好使用它代替ID号。这样,当记录更新时,您也可以修改该时间戳,输入插件将提取记

  • 问题内容: 在Objective- C中,我调用该方法来记录异常。如何在Swift中调用它? 问题答案: 使用Swift 2,您可以将Swift函数和闭包作为C函数指针传递 原始答案 从Xcode 6 beta 6开始,您不能这样做。 Swift确实支持传递函数指针,但是它们几乎就像不透明指针一样被对待。您既不能定义指向Swift函数的C函数指针,也不能在Swift中调用C函数指针。 这意味着您从

  • 问题内容: 这个问题在很多地方都被问到,变化不尽。例如Java-getClassLoader()。getResource()不仅使我烦恼不已。)我仍然无法使其正常工作。 这是一个代码片段: 此作品-请注意,我硬编码的路径,包含剪辑文件,该文件的目录 是 有,而且 是 在同一目录作为我的.class文件。las,注释掉的代码仅返回url的空值。 其他大多数帖子似乎都涉及getResourceAsSt

  • 并且显示错误 正如您所看到的,当我单击Button时,我想从CurrentWeatherFragment调用一个方法,从ForecastWeatherFragment调用一个方法。

  • 问题内容: 我使用RedisConnection Set方法设置字节数组,但是如何获取数据?get返回包装的字节数组吗? 链接: http://code.google.com/p/booksleeve/ http://code.google.com/p/protobuf-net/ 这可行,但感觉不对: 更多信息: 问题答案: 那是完全正确的。“ Get”(BookSleeve)返回一个deferr