【问题标题】:Reset/clear viewmodel or livedata重置/清除视图模型或实时数据
【发布时间】:2021-06-03 15:25:32
【问题描述】:

我遵循 Google 建议的 one-single-activity 应用模式,所以如果我想在 Fragments 之间共享数据,我必须共享一个 ViewModel,其所有者必须是父级Activity所以,问题就变成了,因为我只想在两个 Fragment 之间共享数据,独立于其他 Fragment。

假设我有MainFragmentCreateItemFragmentScanDetailFragment。因此,从第一个导航到 CreateItemFragment,每当我按下按钮时,我导航到 ScanDetailFragment 以扫描条形码,因此,通过 ViewModel 内的 LiveData 对象,我可以将扫描的值返回到 CreateItemFragment一旦 ScandDetailFragment 完成。当我决定取消项目的创建时,问题就出现了:我回到“MainFragment”,因为 ViewModel 的所有者是 Activity 的生命周期,一旦我再次进入 CreateItemFragment,之前扫描的值仍然存在。

有没有办法重置 ViewModel?

【问题讨论】:

  • 我建议您不要共享相同的视图模型,而是在片段之间传递数据。这直接解决了您的问题,没有复杂的逻辑,并且更符合单一责任原则(每个视图模型处理自己的视图)。作为替代覆盖 onBackPressed() 并在转换到上一个片段之前重置视图模型。
  • 但是,Viewmodels 不是也旨在在不同视图之间共享数据吗?否则我不知道如何将数据从片段 C 传递回 B...以及如何重置视图模型?
  • 视图模型是特定视图的模型,因此在不同视图之间共享单个视图模型会破坏视图模型的目的,并且会在视图中进行更改和逻辑 -模型比必要的复杂(您的问题是不必要的复杂性的一个例子)。您可以使用导航组件 (this is how I do it) 在片段之间传递数据。要重置视图模型,只需创建一个 reset() 方法并从片段中调用它。

标签: android android-fragments android-livedata android-viewmodel android-navigation


【解决方案1】:

但是,Viewmodel 不是也旨在在不同视图之间共享数据吗?

没有。每个视图模型应该负责一个视图。 “共享视图模型”模式适用于当您有一个大视图(即活动)具有多个需要共享数据/状态的子视图(即片段)的情况,例如the master / detail example in the documentation。当您需要子视图之间的实时更新时,这对这些情况很方便。

在您的情况下,您是在片段之间导航,因此应该通过转换传递数据。这意味着passing arguments along when starting new fragmentsregistering for results when they complete their task

然后,您的每个片段都是孤立的、独立的、更易于测试的,并且您最终不会得到一个执行 All The Things™ 的 God-ViewModel 并在您尝试跳过复杂会计时变成一团糟对于它可能处于的每个状态。

【讨论】:

  • 没错,很好解释。
  • 感谢 @m0skit0 和 dominicoder。所以检查你的链接,我已经看到有几个选项:将 ViewModel 集成到嵌套导航图中或使用 FragmentManager 侦听器。再次感谢您
【解决方案2】:

在这种情况下,您可以使用回调在片段之间共享数据。或者如果您使用 DB/SharedPreference/Content provider,那么您不必担心共享数据每个页面都会从存储中获取自己的数据(DB/SharedPreference/Contentprovider)。

如果本指南有帮助,您也可以尝试https://medium.com/@lucasnrb/advanced-viewmodels-part-iii-share-a-viewmodel-between-fragments-59c014a3646

【讨论】:

  • 来自商店?你是什​​么意思?
  • 我认为他的意思是数据存储库(从 MVVM 架构的角度来看)
【解决方案3】:

每次从MainFragment进入CreateItemFragment,都可以清除LiveData的值。

或者你可以从onBackPressed()方法中的CreateItemFragment清除它。

【讨论】:

    【解决方案4】:

    当您取消创建项目时,将 livedata 值设置为 null。然后在观察者代码中 if(updatedvalue!=null) 使用更新的实时数据值编写代码。这样您可以避免最后更新的值。

    【讨论】:

      【解决方案5】:

      目前(2022 年),方法 viewmodel.getViewModelStore.clear();onCleared(); 已弃用

      所以,如果你想清除 ViewModel 持有的数据或清除 LiveData 的值,你只需要像这样使用 1 行代码:

      mainViewModel.getLiveData().getValue().clear();
      
      • getLiveData() 是我在 MainViewModel 类中返回 liveData 变量的方法
      • getValue() 是 LiveData 提供的默认方法 (MutableLiveData: setValue(), postValue())

      如果您需要在Fragment中按下Back按钮时清除数据,您可以像下面的代码一样将其放入onViewCreated方法中 - LifecycleFragment的方法。

      private void handleOnBackPressed() {
              requireActivity().getOnBackPressedDispatcher().addCallback(new OnBackPressedCallback(true) {
                  @Override
                  public void handleOnBackPressed() {
                      Objects.requireNonNull(mainViewModel.getLiveData().getValue()).clear();
                      requireActivity().finish();
                  }
              });
          }
      

      如果你想参考代码,我在 Git 上的项目(它仍在更新): https://github.com/Nghien-Nghien/PokeAPI-Java/blob/master/app/src/main/java/com/example/pokemonapi/fragment/MainFragment.java

      【讨论】:

        猜你喜欢
        • 2015-11-29
        • 1970-01-01
        • 2012-06-11
        • 1970-01-01
        • 2014-01-07
        • 1970-01-01
        • 2021-08-24
        • 2016-02-19
        • 2023-03-17
        相关资源
        最近更新 更多