簡體   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