1

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

适配器:

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);
        }
    }
}

可绑定视图持有者:

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,因此我不会在ViewModels内部创建它们,Adapter而是在它们各自的Android.View. 我想这是有道理的,因为我Adapter可能有 XAndroid.View类型,那些视图可以有 YViewModel等等......

基础视图:

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 几乎是其他注入器的副本。”

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

谢谢你的时间。

ps:我已经使用了Adapter示例,但是如果我想使用视图而不是片段,这种方法是相同的。与Adapters您一起仅限于查看。

4

2 回答 2

2

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

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

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

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

简而言之,模型数据对象应该是“哑”的。对于ViewModel个人来说也是如此ViewHolder。可以是“智能的Adapter”并且可以采用经过测试的“智能”依赖项(例如ViewModelFactory必要时),并且Adapter可以使用 Dagger 2 将其注入到您的 Activity 或 Fragment 中。

于 2017-08-05T05:53:19.890 回答
0

虽然我同意大卫不应该这样做的回答,但如果你仍然想这样做,可以通过活动:

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)

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

于 2021-04-30T09:03:15.570 回答