根據(jù)Android 基于Databinding 的入門級 MVVM 模式搭建
我們成功的搭建了MVVM中的View,Databinding,ViewModel之間的關(guān)系僧凰,同時我們也加入了專門負責處理網(wǎng)絡(luò)請求和相關(guān)數(shù)據(jù)請求的model模塊(presenter包,為了防止出現(xiàn)混淆框弛,我們在此處將presenter更改為model命名方式)箫攀,但這只不過是最原始版的MVVM雛形庄蹋,用起來并沒有方便多少壶愤,現(xiàn)在我們對他們進行進一步封裝领曼。
1.建立一個大致的目錄:
1.application包用于放置基礎(chǔ)Application抹剩,用于后續(xù)我們放置可能涉及到的基礎(chǔ)組件初始化司抱;
2.activity包放置基礎(chǔ)BaseDBActivity封裝以及可能會用到的特殊需求的基礎(chǔ)Activity;
3.base包用于放置BaseActivity,BaseFragment諸如此類的基礎(chǔ)類,方便我們根據(jù)業(yè)務(wù)需要做統(tǒng)一封裝的入口铐炫;
4.fragment包放置基礎(chǔ)BaseDBFragment封裝以及可能會用到的特殊需求的基礎(chǔ)Fragment;
5.model包用于放置model層基礎(chǔ)封裝類,如BaseModel垒手;
6.vm包用于放置vm層基礎(chǔ)封裝類,如BaseVM;
2.封裝BaseDBActivty:
我們原始的Activity要將Databinding跟VM串聯(lián)起來倒信,我們是在Activity內(nèi)操作的科贬,代碼如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
MainVM mainVM = new ViewModelProvider(this).get(MainVM.class);
binding.setViewModel(mainVM);
}
}
那么此處我們需要把每個View和VM綁定的細節(jié)封裝到BaseDBActivity內(nèi),以后我們就不用再每次都寫這么兩句代碼了鳖悠,封裝以后代碼如下:
public abstract class BaseBDActivity extends BaseActivity {
protected ViewDataBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bindLayout();
}
protected void bindLayout(){
binding = DataBindingUtil.setContentView(this, getLayoutId());
//MainVM mainVM = new ViewModelProvider(this).get(MainVM.class);
//binding.setViewModel(mainVM);
}
public abstract int getLayoutId();
}
這里我們可以看到榜掌,經(jīng)過簡單的封裝,我們現(xiàn)在MainActivity已經(jīng)變成了:
public class MainActivity extends BaseBDActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public int getLayoutId() {
return R.layout.activity_main;
}
}
但此時我們無法獲取具體的Databinding用于調(diào)用binding.setViewModel(new MainVM());這一步數(shù)據(jù)綁定乘综,我們注意到DataBindingUtil.setContentView返回的是一個泛型<T extends ViewDataBinding>憎账,也就是說我們其實可以拿到具體的Databinding引用類型:ActivityMainBinding,從而我們可以手動完成數(shù)據(jù)綁定卡辰,于是我們可以進一步優(yōu)化BaseBDActivity:
public abstract class BaseBDActivity<T extends ViewDataBinding> extends BaseActivity {
protected T binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bindLayout();
}
protected void bindLayout(){
binding = DataBindingUtil.setContentView(this, getLayoutId());
//MainVM mainVM = new ViewModelProvider(this).get(MainVM.class);
//binding.setViewModel(mainVM);
}
public abstract int getLayoutId();
}
現(xiàn)在我們現(xiàn)在MainActivity已經(jīng)變成了:
public class MainActivity extends BaseBDActivity<ActivityMainBinding> {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MainVM mainVM = new ViewModelProvider(this).get(MainVM.class);
binding.setViewModel(mainVM);
}
@Override
public int getLayoutId() {
return R.layout.activity_main;
}
}
接下來胞皱,我們需要將binding.setViewModel這一步優(yōu)化掉,通過強行設(shè)定Layout的ViewModel命名為viewModel九妈,我們可以通過ViewDatabinding.setVariable(int variableId, @Nullable Object value)方法規(guī)避掉binding.setViewModel(mainVM)這種無法通用的問題反砌,也就是在Layout布局文件中,我們對ViewModel的引入是寫死的:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<!--此處綁定viewModel(封裝的原因我們這里固定命名為:viewModel)-->
<variable
name="viewModel"
type="com.jf.mvvm_1.work.vm.MainVM" />
</data>
</layout>
而我們可以通過傳入Class<?> clz 也可以直接封裝new ViewModelProvider(this).get(MainVM.class)這一步允蚣,最終變?yōu)椋?/p>
public abstract class BaseBDActivity<T extends ViewDataBinding> extends BaseActivity {
protected T binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bindLayout();
}
protected void bindLayout(){
bindLayout(getViewModelClass());
}
protected void bindLayout(Class<? extends ViewModel> clzVM){
bindLayout(new ViewModelProvider(this).get(clzVM));
}
protected <X extends ViewModel> void bindLayout(X vm){
binding = DataBindingUtil.setContentView(this, getLayoutId());
binding.setLifecycleOwner(this);
binding.setVariable(BR.viewModel,vm);
}
public abstract int getLayoutId();
protected abstract Class<? extends ViewModel> getViewModelClass();
}
而此時我們的MainActivity的代碼簡化為:
public class MainActivity extends BaseBDActivity<ActivityMainBinding> {
@Override
public int getLayoutId() {
return R.layout.activity_main;
}
@Override
protected Class<? extends ViewModel> getViewModelClass() {
return MainVM.class;
}
}
然后我們注意到通過反射機制獲取泛型的類類型:((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()可以獲取泛型的Class類型于颖,我們可以進一步封裝為泛型指定類型:
public abstract class BaseBDActivity<T extends ViewDataBinding,X extends ViewModel> extends BaseActivity {
protected T binding;
protected X viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bindLayout();
}
protected void bindLayout(){
bindLayout(getViewModelClass());
}
protected void bindLayout(Class<X> clzVM){
bindLayout(new ViewModelProvider(this).get(clzVM));
}
protected void bindLayout(X vm){
viewModel = vm;
binding = DataBindingUtil.setContentView(this, getLayoutId());
binding.setLifecycleOwner(this);
binding.setVariable(BR.viewModel,vm);
}
public abstract int getLayoutId();
//protected abstract Class<? extends ViewModel> getViewModelClass();
public Class<X> getViewModelClass() {
Class<X> xClass = (Class<X>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];
return xClass;
}
}
最終我們的MainActivity的代碼簡化為:
public class MainActivity extends BaseBDActivity<ActivityMainBinding,MainVM> {
@Override
public int getLayoutId() {
return R.layout.activity_main;
}
}