[英]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.