MVVM 架构相对于MVP来说其实思想上是一致的,只是MVP中的P层在MVVM中换成了ViewModel,所以MVVM的模块结构如下图(截图出自https://developer.android.google.cn/jetpack/guide)
这里面的LiveData 和Room 其实都是Google一直在推的JetPack 中的组件,更多的组件大家可以去https://developer.android.google.cn/jetpack 中查看
回到MVVM 在MVVM中使用ViewModel 和LiveData 要引入依赖,因为现在我们的项目一般都迁移到了AndroidX,所以就不需要单独进行引入了,而且AndroidX还引入了LifeCycle,可以很方便进行生命周期的管理,防止内存泄漏(如果要单独引入,可以这样)
dependencies {
def lifecycle_version = "2.2.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
...
}
依赖好了,我们最好再启用DataBinding ,这里我只使用DataBinding 的findViewById 功能,这也是官方一直推荐的,而且Butterknife现在已经停更了,官方说明中是这样说的This tool is now deprecated. Please switch to view binding. 所以我们没有理由不使用DataBinding
首先在build.gradle中的android{}启用
dataBinding {
enabled = true
}
然后将我们的布局最外层套一层layout,像这样
接下来我们开始封装MVVM,它其实是MVP的封装思想是一样的,所以这里我们如果熟知MVP,是非常好理解的,先贴下代码
public abstract class BaseActivity<VM extends BaseViewModel,V extends ViewDataBinding> extends AppCompatActivity implements IBaseView {
protected VM viewModel;
protected V viewBinding;
protected LoadingUtils loadingUtil;
protected ToastUtils customToastUtils;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewBinding = DataBindingUtil.setContentView(this,setLayoutRes());
initParam();
//初始化ViewModel
initViewModel();
initView();
initToolBar();
initData();
initViewObservable();
}
protected abstract void initView();
protected abstract int setLayoutRes();
private void initViewModel() {
viewBinding.setLifecycleOwner(this);
//获取ViewModel实例
ViewModelProvider viewModelProvider = new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication()));
//获取返回直接继承的父类(包含泛型参数)
ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();
if (parameterizedType != null){
//
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
Class<VM> tClass = (Class<VM>) actualTypeArguments[0];
viewModel = viewModelProvider.get(tClass);
getLifecycle().addObserver(viewModel);
}
}
private void initToolBar() {
}
@Override
public void initParam() {
loadingUtil = new LoadingUtils(this);
customToastUtils = ToastUtils.getDefaultMaker().setGravity(Gravity.CENTER,0,0)
.setDurationIsLong(true).setMode(ToastUtils.MODE.DARK);
}
@Override
public void initData() {
}
@Override
public void initViewObservable() {
}
@Override
public void onContentReload() {
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
在基类中,通过泛型,来将一些重复的代码进行封装,对于BaseModel,StateLiveData大家可以不用关心,这里主要针对一些Rxjava 发送的一些请求,在具体的ViewModel 中添加进来,并且在ViewModel 生命周期结束的时候进行清空,可以避免内存泄漏
public class BaseViewModel extends AndroidViewModel implements IBaseViewModel, Consumer<Disposable> {
protected StateLiveData<Object> stateLiveData;
private CompositeDisposable compositeDisposable;
public BaseViewModel(@NonNull Application application) {
super(application);
compositeDisposable = new CompositeDisposable();
stateLiveData = new StateLiveData<Object>();
}
public StateLiveData<Object> getStateLiveData() {
return stateLiveData;
}
@Override
public void onAny() {
}
@Override
public void onCreate() {
}
@Override
public void onDestroy() {
}
@Override
public void onStart() {
}
@Override
public void onStop() {
}
@Override
public void onResume() {
}
@Override
public void onPause() {
}
@Override
public void accept(Disposable disposable) throws Exception {
compositeDisposable.add(disposable);
}
@Override
protected void onCleared() {
super.onCleared();
if (compositeDisposable != null && compositeDisposable.size() > 0){
compositeDisposable.clear();
compositeDisposable = null;
}
}
}
具体的ViewModel 中,就是进行网络请求和简单的数据处理,将结果通过LiveData型的数据传递给Activity或Fragment,
class HomeViewModel(application: Application) : BaseViewModel(application) {
val liveData = MutableLiveData<HomeArticleListResponse>()
val errorLiveData = MutableLiveData<String>()
fun getHomeArticle(pageNum: Int) {
stateLiveData.postLoading()
AppRequest.get().getHomeArticalList(pageNum)
.compose(RxUtils.observableToMain())
//绑定当前VIewModel 的生命周期 ViewModel
.doOnSubscribe(this)
.subscribe(object : BaseObserver<HomeArticleListResponse>() {
override fun onSuccess(baseResponse: BaseResponse<HomeArticleListResponse>) {
if (baseResponse.data == null) {
errorLiveData.postValue(ViewModelConst.SUCCESSNODATA)
} else {
liveData.postValue(baseResponse.data)
}
stateLiveData.postSuccess()
}
override fun onCodeError(baseResponse: BaseResponse<*>) {
errorLiveData.postValue(baseResponse.errorMsg)
stateLiveData.postError()
}
override fun onFailure(exception: ResponseCustomException) {
errorLiveData.postValue(exception.message)
stateLiveData.postError()
}
})
}
}
在Activity中获取结果也很方便,从viewModel中拿到对应的LiveData,作数据的监听就可以了,LiveData 获取到数据会自动进行数据的填充,
viewModel.liveData.observe(this,
androidx.lifecycle.Observer<HomeArticleListResponse> {
val datas = it.datas
val curPage = it.curPage
if (pageNum == 0) {
articleListAdapter!!.setNewData(datas)
} else {
if (curPage >= it.pageCount) {
//没有页了
viewBinding.homeSmartRl.finishLoadMoreWithNoMoreData()
} else {
if (datas != null && datas.isNotEmpty()) {
articleListAdapter!!.addData(datas)
} else {
viewBinding.homeSmartRl.finishLoadMore(false)
}
}
}
})
以上就是MVVM的一些简单封装使用,大家可以结合项目实际再做加工,毕竟封装的习惯每个人都不一样,只要了解了思想,都只是一种形式。