如果没有干净的解决方案,我的方法有什么问题
建筑学?我应该在这种情况下使用片段吗?
是的,片段是正确的选择
总结:
- 除了将
Views 绑定到LiveData 之外,没有其他真正的替代方法。
- 如果使用
LiveData,则需要LifeCycle。
- 如果序列中子视图的生命周期应该比活动的生命周期短,那么片段就是要走的路。
详情
除了将Views 绑定到LiveData 之外,别无选择。
视图模型不应持有对视图的未终止引用,否则只要视图模型存在,视图就会存在,从而导致内存泄漏。共有三种观察者模式来讨论视图如何观察视图模型。
a.) 可变实时数据
它们需要一个生命周期。当生命周期结束时,引用会自动清理。这是推荐的解决方案。
b.) 弱引用
理论上这应该可行。当最后一个对视图的硬引用消失时,垃圾收集器应该清理弱引用。在实践中,解决方案是不稳定的,有时引用会过早地消失。
c.) 手工观察者
手工观察者必须调用 remove 方法。不幸的是,当视图消失时,没有定义的破坏钩子。视图中没有地方可以调用remove方法。
因此,根据我的经验,a.) 是唯一可能的解决方案。
LiveData 片段需要生命周期
这里提到的子视图是按顺序创建的。如果我们将它们绑定到 Activity,它们会堆积起来直到 Activity 消失,尽管它们只需要在序列中的一小段时间间隔内使用。
片段可以存在于活动时间的一小部分。它们是将序列的子视图绑定到它们的正确解决方案。
示例代码
测验在这里被称为挑战。 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> {
[...]
}