Android 如何使用临时子视图生成组合视图模型? 脚本

Android 如何使用临时子视图生成组合视图模型? 脚本,android,android-fragments,viewmodel,android-viewmodel,Android,Android Fragments,Viewmodel,Android Viewmodel,我有一个测验生成器,它可以生成一系列不同类别的测验。序列的长度是无限的 测验生成器有一个视图模型。每种类型的测验都有一个视图模型。测验生成器视图模型应根据测验的类别创建测验的视图模型 问题 视图模型不能包含对生命周期的引用,但我需要生命周期来创建视图模型 ViewModelProviders.of(lifecycle).get(classForQuizzType); 问题 我在哪里创建测验的子视图模型 我能想到的一个解决方案是每次从活动中注入子视图模型。这是一个迂回的过程,尤其是当涉及嵌套视图

我有一个测验生成器,它可以生成一系列不同类别的测验。序列的长度是无限的

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

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

ViewModelProviders.of(lifecycle).get(classForQuizzType);
问题 我在哪里创建测验的子视图模型

我能想到的一个解决方案是每次从活动中注入子视图模型。这是一个迂回的过程,尤其是当涉及嵌套视图时

另一种解决方案是在嵌套视图中创建视图模型,这看起来也很难看,因为从视图内部访问生命周期不是常见的做法


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

我是在
pskink
的启发下给出第一个答案的。也许我会在体验了建议的方法之后更新答案

如果视图模型应生成子对象(又称组件),则只要主对象绑定到生命周期,并且组件从主对象引用,组件就不需要绑定到生命周期本身

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

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

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

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

如果没有干净的解决方案,我的方法有什么问题 建筑学我应该在这种场景中使用片段吗

是的,碎片是正确的选择 总结:
  • 除了通过
    LiveData
    绑定
    视图
    ,没有真正的替代方法
  • 如果使用
    LiveData
    则需要
    生命周期
  • 如果序列中的子视图的生命周期应该比活动的生命周期短,那么片段就是最好的选择
  • 细节 除了通过
    LiveData
    绑定
    视图
    ,没有真正的替代方法。 视图模型不应包含对视图的未终止引用,否则只要视图模型存在,视图就会存在,从而导致内存泄漏。有三种观察者模式可以讨论视图如何观察视图模型

    a、 )可变LiveData

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

    b、 )weakreference

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

    c、 )手工制作的观察员

    手工观察者必须调用移除方法。不幸的是,当视图消失时,没有定义的销毁挂钩。视图中没有调用remove方法的位置

    因此,根据我的经验,a.)是唯一可能的解决办法

    因为LiveData需要生命周期,所以碎片是一种方式 这里提到的子视图是按顺序创建的。如果我们将它们绑定到活动上,它们会堆积起来,直到活动消失,尽管它们只需要一小段时间

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

    示例代码 测验在这里被称为挑战。
    fragmentmanager
    始终是活动的管理者,而
    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> {
      [...]
    }
    
    #视图的视图模型接受程序接口
    公共接口ViewModelAcceptor{
    void-plugview模型(
    T视图模型,
    生命周期所有者生命周期所有者,
    碎片管理器碎片管理器
    );
    }
    #在挑战的父视图类中,将创建新的挑战
    #依次
    ChallengeFragment ChallengeFragment=新的ChallengeFragment();
    challengeFragment.setchallengeview模型(challengeview模型);
    FragmentTransaction FragmentTransaction=fragmentManager.beginTransaction();
    fragmentTransaction.replace(this.getId(),challengeFragment);
    fragmentTransaction.commit();
    #挑战者
    公共类challengeragment扩展了片段{
    私有challengeview模型challengeview模型;
    @可空
    @凌驾
    创建视图时的公共视图(LayoutFlater充气机、@Nullable ViewGroup容器、Bundle savedInstanceState){
    返回新的ChallengeView(getActivity(),null);
    }
    public void setChallengeViewModel(ChallengeViewModel ChallengeViewModel){
    this.challengeViewModel=challengeViewModel;
    }
    @凌驾
    ActivityCreated上的公共无效(@Nullable Bundle savedinStateCState){
    super.onActivityCreated(savedInstanceState);