如何使用临时子视图生成合成视图模型?

时间:2018-04-18 08:16:09

标签: android android-fragments viewmodel android-viewmodel

方案

我有一个quizz生成器,它生成一系列不同类的测验。序列长度不限。

有一个quizz生成器的视图模型。每种类型的quizz都有一个视图模型。 quizz生成器视图模型应根据其类创建测验的视图模型。

问题

视图模型不能包含对生命周期的引用,但我需要生命周期来创建视图模型。

ViewModelProviders.of(lifecycle).get(classForQuizzType);

问题

我在哪里创建测验的子视图模型?

我能想到的一个解决方案是每次从活动中注入子视图模型。这是一个绕道而行,尤其是涉及嵌套视图时。

另一个解决方案是在嵌套视图中创建视图模型,这看起来也很丑陋,因为从视图内部访问生命周期并不常见。

如果没有干净的解决方案,我的架构方法有什么问题?我应该在这种情况下使用片段吗?

2 个答案:

答案 0 :(得分:2)

我自pskink启发了自己的第一个答案。也许我会在对建议的方法有一些经验之后更新答案。

如果视图模型应生成子对象(即组件),则只要主对象绑定到生命周期并且组件从主服务器引用,组件就不需要自己绑定到生命周期。 / p>

对于给定的示例,这意味着创建主对象的好地方位于活动的顶级位置,lifecycle可直接使用。 quizz对象是从主对象引用的。他们不需要直接访问生命周期,可以在任何地方创建,例如在主对象内部。这样可以按需创建它们。

组件可能是也可能不是ViewModel的子类。我认为扩展ViewModel是一种很好的做法。此父类引入onCleared方法。这是从基础模型中删除观察者的地方。如果不这样做,您可能会造成内存泄漏。

您必须注意在适当的时刻致电onCleared,至少从主对象的onCleared方法开始。在这种特殊情况下,必须在生成新的quizz之前清除每个先前的quizz,以从基础quizz模型中删除引用。

可以使用new关键字简单地创建组件的视图模型。无需使用工厂或提供商。

答案 1 :(得分:0)

  

如果没有干净的解决方案,我的方法有什么问题   建筑?我应该在这种情况下使用片段吗?

是的,片段是正确的选择

要点:

  1. 除了Views之外,没有真正的替代LiveData
  2. 如果使用LiveData则需要LifeCycle
  3. 如果序列中子视图的生命周期应该比活动的生命周期短,那么碎片就是可行的方法。
  4. 详细

    除了Views {/ 1}}之外没有真正的替代LiveData。{/ h3>

    视图模型不应保存对视图的未终止引用,否则只要视图模型存在导致内存泄漏,视图就会存在。有三种观察者模式可以讨论视图如何观察视图模型。

    a。)MutableLiveData

    他们需要一个生命周期。生命周期结束时,将自动清理引用。这是推荐的解决方案。

    b。)WeakReferences

    理论上这应该有用。当对视图的最后一个硬引用消失时,垃圾收集器应该清除弱引用。在实践中,解决方案是不稳定的,有时参考会过早消失。

    c。)手工观察员

    手工制作的观察者必须调用删除方法。不幸的是,当一个视图消失时,没有定义的破坏钩子。没有地方可以在视图中调用remove方法。

    因此,根据我的经验,。)是唯一可行的解​​决方案。

    由于LiveData片段需要生命周期才能实现

    此处提到的子视图是按顺序创建的。如果我们将它们绑定到活动上,它们会堆积起来直到活动消失,尽管它们只需要在一小段时间内按顺序进行。

    片段可以存在于活动时间的子部分。它们是将序列的子视图绑定到它们的正确解决方案。

    示例代码

    这里的测验被称为挑战。 FragmentManger始终是活动的LifecycleOwner,而# A view model acceptor interface for views public interface ViewModelAcceptor<T extends ViewModel> { void plugViewModel( T viewModel, LifecycleOwner lifecycleOwner, FragmentManager fragmentManager ); } # In the parent view class of the challenges new challenges are created # in sequence ChallengeFragment challengeFragment = new ChallengeFragment(); challengeFragment.setChallengeViewModel(challengeViewModel); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.replace(this.getId(), challengeFragment); fragmentTransaction.commit(); # ChallengeFragment public class ChallengeFragment extends Fragment { private ChallengeViewModel challengeViewModel; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { return new ChallengeView(getActivity(), null); } public void setChallengeViewModel(ChallengeViewModel challengeViewModel) { this.challengeViewModel = challengeViewModel; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); ChallengeView challengeView = (ChallengeView) getView(); Objects.requireNonNull(challengeView) .plugViewModel(challengeViewModel, this, getFragmentManager()); } } # Challenge views are the child views of the sequence public class ChallengeView extends ConstraintLayout implements ViewModelAcceptor<ChallengeViewModel> { [...] } 是活动或片段。

    <form [formGroup]="form">
        <input type="text" id="name" fromControlName="name" />
        <input type="text" id="age" fromControlName="age" />
    </form>