繁体   English   中英

使用 MVVM 架构的 ViewModel 注入(内部视图)

[英]ViewModel injection (inside View) with MVVM Architecture

这就是我使用MVVM (+Databinding)Dagger-2.11-rc2创建Adapter

适配器:

public class ItemAdapter extends RecyclerView.Adapter<BindableViewHolder<ViewDataBinding>>{
    private static int TYPE_A = 0;
    private static int TYPE_B = 1;

    ...

    @Override
    public BindableViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == TYPE_A) {
            return new ItemViewHolder(new ItemRowView(parent.getContext()).getBinding());
        }
        ...
    }

    @Override
    public void onBindViewHolder(BindableViewHolder holder, int position) {
        if (holder.getItemViewType() == TYPE_A) {
            ((ItemViewHolderBinding) holder.getBinding()).getViewModel().setItemModel(((ItemModel) getItem(position)));
        }        
        ...
    }

    private static class ItemViewHolder extends BindableViewHolder<ItemViewHolderBinding> {
        ItemViewHolder(ItemViewHolderBinding binding) {
            super(binding);
        }
    }
}

BindableViewHolder:

public abstract class BindableViewHolder<ViewBinding extends ViewDataBinding> extends RecyclerView.ViewHolder {

    private ViewBinding mBinding;

    public BindableViewHolder(ViewBinding binding) {
        super(binding.getRoot());
        mBinding = binding;
    }

    public ViewBinding getBinding(){
        return mBinding;
    }
}

由于我使用的是 Dagger,因此我不会在Adapter内创建ViewModels ,而是在各自的Android.View内创建(注入)它们。 我想这是有道理的,因为我的Adapter可能有 X Android.View类型,这些视图可以有 Y ViewModel等......

基本视图:

public abstract class BaseView<ViewBinding extends ViewDataBinding, ViewModel extends BaseViewModel> extends FrameLayout {

    @Inject
    ViewModel mViewModel;
    protected ViewBinding mBinding;

    protected abstract void initBinding(final ViewBinding binding, final ViewModel viewModel);

    ...

    private void initView(Context context) {
        ViewInjection.inject(this);

        mBinding = DataBindingUtil...
        initBinding(mBinding, mViewModel);
        ...
    }
    ...
}

基础视图模型

public class BaseViewModel extends BaseObservable {...}

ItemRowView(或任何视图):

public class ItemRowView extends BaseView<ItemRowViewBinding, ItemRowViewModel> {

    @Inject
    ViewModelA mViewModelA;
    @Inject
    ViewModelB mViewModelB;
    ...

    @Override
    protected void initBinding(ItemRowViewBinding binding, ItemRowViewModel viewModel) {
        binding.setViewModel(viewModel);
        binding.setViewModelA(mViewModelA);
        binding.setViewModelB(mViewModelB);
        ...
    }
}

现在,这种方法适用于活动、片段等,但是当我使用视图时,我必须创建一个ViewInjecton,因为 Dagger 没有开箱即用。 我就是这样做的(阅读直到您到达“ViewInjection 几乎是其他 Injector 的副本。”

我的问题是(是):这是一个好方法吗? 我是否正确使用了 MVVM 和 Dagger? 在不创建ViewInjecton (并使用 Dagger-2.11)的情况下,有没有更好的方法来实现这一点?

谢谢你的时间。

ps:我使用了Adapter示例,但是如果我想使用视图而不是片段,这种方法是相同的。 使用Adapters您只能使用视图。

这个问题中,已经有一些关于是否应该在 Views 中注入的讨论。

由于我使用的是 Dagger,因此我不会在 Adapter 内创建 ViewModel,而是在各自的 Android.View 内创建(注入)它们。 我想这是有道理的,因为我的 Adapter 可能有 X And​​roid.View 类型,这些视图可以有 Y ViewModel 等......

我个人觉得这有点问题,如果我在一个使用该代码的团队工作,我更喜欢层之间的更大程度的分离。 至少,

  1. 应该有一个清晰的模型层(例如从存储库或云中检索)。 这些应该只是数据对象。
  2. 如果模型层很容易与“项目”层相关,即RecyclerView的支持List的内容,则Adapter可以直接处理模型层。
  3. RecyclerView.ViewHolderViewModel应该非常轻量级并且不需要注入。 它本质上应该是一组属性,可以轻松转换为视图的某些属性(例如, setText()setColor() )并且可以获取/设置。 这些可以使用适配器中onBindViewHolder方法中的new关键字创建。 如果这很困难,您可以提取一个工厂( ViewModelFactory )并将其作为您的适配器的依赖项注入。

简而言之,模型数据对象应该是“哑巴”。 对于单个ViewHolderViewModel也是ViewHolder Adapter可以是“智能的”,并且可以采用经过测试的“智能”依赖项(如必要时的ViewModelFactory ),并且可以使用 Dagger 2 将此Adapter注入到您的活动或片段中。

虽然我同意David 的回答,即不应这样做,但如果您仍想这样做,则可以通过以下活动进行:

override val activity: FragmentActivity by lazy {
    try {
        context as FragmentActivity
    } catch (exception: ClassCastException) {
        throw ClassCastException("Please ensure that the provided Context is a valid FragmentActivity")
    }
}
override var viewModel = ViewModelProviders.of(activity).get(SharedViewModel::class.java)

此处将对此进行更详细的讨论。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM