[英]ViewModel injection (inside View) with MVVM Architecture
This is how I create an Adapter
with MVVM (+Databinding) and Dagger-2.11-rc2 :这就是我使用MVVM (+Databinding)和Dagger-2.11-rc2创建Adapter
:
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: 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;
}
}
Since I'm using Dagger I wont be creating the ViewModels
inside the Adapter
instead they will be created (injected) inside their respective Android.View
.由于我使用的是 Dagger,因此我不会在Adapter
内创建ViewModels
,而是在各自的Android.View
内创建(注入)它们。 And I guess it makes sense because my Adapter
may have X Android.View
types, those views can have Y ViewModel
, etc...我想这是有道理的,因为我的Adapter
可能有 X Android.View
类型,这些视图可以有 Y ViewModel
等......
BaseView:基本视图:
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);
...
}
...
}
BaseViewModel :基础视图模型:
public class BaseViewModel extends BaseObservable {...}
ItemRowView (or any View): 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);
...
}
}
Now, this approach works fine with Activities, Fragments, etc, but when I use Views I have to create a ViewInjecton because Dagger doesn't have it out of the box.现在,这种方法适用于活动、片段等,但是当我使用视图时,我必须创建一个ViewInjecton,因为 Dagger 没有开箱即用。 This is how I do it (read until you've reached "ViewInjection is pretty much a copy from other Injectors." ) 我就是这样做的(阅读直到您到达“ViewInjection 几乎是其他 Injector 的副本。” )
My question(s) is(are): Is this a good approach?我的问题是(是):这是一个好方法吗? I'm I using MVVM and Dagger correctly?我是否正确使用了 MVVM 和 Dagger? Is there any better way to achieve this without creating ViewInjecton (and using Dagger-2.11)?在不创建ViewInjecton (并使用 Dagger-2.11)的情况下,有没有更好的方法来实现这一点?
Thanks for your time.谢谢你的时间。
ps: I've used the Adapter
example but this approach is the same if I want to use Views instead of Fragments. ps:我使用了Adapter
示例,但是如果我想使用视图而不是片段,这种方法是相同的。 With Adapters
you are restricted to Views.使用Adapters
您只能使用视图。
There has already been some discussion about whether one should inject inside Views or not in this question .在这个问题中,已经有一些关于是否应该在 Views 中注入的讨论。
Since I'm using Dagger I wont be creating the ViewModels inside the Adapter instead they will be created (injected) inside their respective Android.View.由于我使用的是 Dagger,因此我不会在 Adapter 内创建 ViewModel,而是在各自的 Android.View 内创建(注入)它们。 And I guess it makes sense because my Adapter may have X Android.View types, those views can have Y ViewModel, etc...我想这是有道理的,因为我的 Adapter 可能有 X Android.View 类型,这些视图可以有 Y ViewModel 等......
I personally find this a little problematic and if I was working on a team with that code I would prefer a greater degree of separation between layers.我个人觉得这有点问题,如果我在一个使用该代码的团队工作,我更喜欢层之间的更大程度的分离。 At least,至少,
Adapter
can deal with the model layer directly if it is easily related to the "item" layer ie, the contents of the backing List
for the RecyclerView
.如果模型层很容易与“项目”层相关,即RecyclerView
的支持List
的内容,则Adapter
可以直接处理模型层。ViewModel
for the RecyclerView.ViewHolder
should be extremely lightweight and not need injection. RecyclerView.ViewHolder
的ViewModel
应该非常轻量级并且不需要注入。 It should essentially be a bag of properties that easily translate into some property of the view (eg, setText()
, setColor()
) and can be get/set.它本质上应该是一组属性,可以轻松转换为视图的某些属性(例如, setText()
、 setColor()
)并且可以获取/设置。 These can be created using the new
keyword inside the onBindViewHolder
method in the adapter.这些可以使用适配器中onBindViewHolder
方法中的new
关键字创建。 If this is difficult, you could extract a Factory ( ViewModelFactory
) and inject that as a dependency for your Adapter.如果这很困难,您可以提取一个工厂( ViewModelFactory
)并将其作为您的适配器的依赖项注入。 In short, the model data objects should be "dumb".简而言之,模型数据对象应该是“哑巴”。 The same goes for the ViewModel
for the individual ViewHolder
.对于单个ViewHolder
的ViewModel
也是ViewHolder
。 The Adapter
can be "intelligent" and can take tested "intelligent" dependencies (such as a ViewModelFactory
if necessary) and this Adapter
can be injected into your Activity or Fragment using Dagger 2. Adapter
可以是“智能的”,并且可以采用经过测试的“智能”依赖项(如必要时的ViewModelFactory
),并且可以使用 Dagger 2 将此Adapter
注入到您的活动或片段中。
While I agree with David's answer that this should not be done, if you still want to do this, it is possible by going through the activity:虽然我同意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.