[英]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 Android.View 类型,这些视图可以有 Y ViewModel 等......
我个人觉得这有点问题,如果我在一个使用该代码的团队工作,我更喜欢层之间的更大程度的分离。 至少,
RecyclerView
的支持List
的内容,则Adapter
可以直接处理模型层。RecyclerView.ViewHolder
的ViewModel
应该非常轻量级并且不需要注入。 它本质上应该是一组属性,可以轻松转换为视图的某些属性(例如, setText()
、 setColor()
)并且可以获取/设置。 这些可以使用适配器中onBindViewHolder
方法中的new
关键字创建。 如果这很困难,您可以提取一个工厂( ViewModelFactory
)并将其作为您的适配器的依赖项注入。 简而言之,模型数据对象应该是“哑巴”。 对于单个ViewHolder
的ViewModel
也是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.