AndroidX设计架构MVVM之DataBinding+ViewModel+LiveData
原文
AndroidX设计架构MVVM之ViewModel创建流程原理分析
AndroidX设计架构MVVM之ViewModel生命周期分析
AndroidX设计架构MVVM之LiveDatal生命周期及数据监听分析
AndroidX设计架构MVVM之DataBinding搭配LiveData的分析
AndroidX设计架构MVVM之DataBinding+ViewModel+LiveData
环境各版本:
android studio 3.5.1
android gradle plugin version 3.5.1
gradle version 5.4.1
ViewModel 2.1.0
LiveData 2.1.0
整体来说MVVM架构的搭建依赖于Android的现有的组件,搭建还是非常简单的,个人觉得最好还是要了解各组件的原理(参考上边链接),提供的Demo非常简单,通过组件化实现,可参考组件化Demo-design-component中modulemvvm
相对于单独使用DataBinding处理业务逻辑来说ObservableField不具备生命周期感知
简单说下为什么要用ViewModel?
ViewModel的生命周期比Activity的生命周期长,当屏幕旋转时不随activity的销毁重建而清除。但是注意ViewModel不是onSaveInstanceState 的替代品,比如当内存不足时,ViewModel随Activity销毁,但onSaveInstanceState 依旧可以执行保存重要数据。
简单说下为什么要用LiveData?
LiveData会记录value的version,并且在inActive状态时,只记录value,不通知观察者更新数据,由inActive状态切换到active状态才通知观察者更新。
1:启用databinding
android {
。。。。。。
//开启DataBinding
dataBinding {
enabled true
}
}
2: 导入需要的组件ViewModel 和 LiveData
在项目的build.gradle中加入如下仓库
allprojects {
repositories {
google()
jcenter()
}
}
加入具体组件详细见注释,可以根据需要选择
dependencies {
//使用的版本
def lifecycle_version = "2.1.0"
// ViewModel and LiveData
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
// alternatively - just ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" // For Kotlin use lifecycle-viewmodel-ktx
// alternatively - just LiveData
implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
// alternatively - Lifecycles only (no ViewModel or LiveData). Some UI
// AndroidX libraries use this lightweight import for Lifecycle
implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" // For Kotlin use kapt instead of annotationProcessor
// alternately - if using Java8, use the following instead of lifecycle-compiler
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
// optional - ReactiveStreams support for LiveData
implementation "androidx.lifecycle:lifecycle-reactivestreams:$lifecycle_version" // For Kotlin use lifecycle-reactivestreams-ktx
// optional - Test helpers for LiveData
testImplementation "androidx.arch.core:core-testing:$lifecycle_version"
}
3:写自己的代码,wtf
用户UserBean
public class UserBean {
private String name;
private String age;
private UserBean() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public static final class UserBeanBuilder {
private String name;
private String age;
private UserBeanBuilder() {
}
public static UserBeanBuilder newBuilder() {
return new UserBeanBuilder();
}
public UserBeanBuilder setName(String name) {
this.name = name;
return this;
}
public UserBeanBuilder setAge(String age) {
this.age = age;
return this;
}
public UserBean build() {
UserBean userBean = new UserBean();
userBean.age = this.age;
userBean.name = this.name;
return userBean;
}
}
}
用户的ViewModel
public class VMUser extends BaseViewModel {
//live data
private MutableLiveData<UserBean> mUserInfo;
public VMUser(@NonNull Application application) {
super(application);
mUserInfo = new MutableLiveData<>();
}
public MutableLiveData<UserBean> getUserInfo() {
return mUserInfo;
}
public void loadUserInfo() {
//模拟网络加载
MainLooper.getInstance().postDelayed(new Runnable() {
@Override
public void run() {
mUserInfo.setValue(UserBean.UserBeanBuilder.newBuilder().setName("我是live data").setAge("12").build());
}
}, 500);
}
public void getWeatherInfo(String city) {
MvvmNetWork.getInstance().getWeatherInfo(city)
.compose(RxjavaUtils.<Weather>>io2main())
.as(this.<Weather>>bindLifecycle())
.subscribe(new BaseObserver<Weather>() {
@Override
public void onSuccess(BaseEntity<Weather> data) {
}
@Override
public void onFailure(int code, Throwable throwable) {
}
});
}
}
展示用户信息的View:主要包含基类和具体的子类
//各View的父类
public abstract class AbstractBaseMvvmActivity<V extends ViewDataBinding, VM extends BaseViewModel> extends AppCompatActivity {
protected V mBinding;
protected VM mViewModel;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, getContentViewId());
if (getVmClass() == null) {
LogUtils.e("getVmClass() == null");
} else {
mViewModel = ViewModelProviders.of(this).get(getVmClass());
//防止Rxjava使用时的内存泄漏
getLifecycle().addObserver(mViewModel);
}
//为livedata添加生命周期
mBinding.setLifecycleOwner(this);
init();
}
protected abstract int getContentViewId();
protected abstract Class<VM> getVmClass();
protected abstract void init();
protected <T> AutoDisposeConverter<T> bindLifecycle() {
return AutoDisposeUtil.bindLifecycle(this);
}
public V getBinding() {
return mBinding;
}
public VM getViewModel() {
if (mViewModel == null) {
throw new NullPointerException("mViewModel==null");
}
return mViewModel;
}
}
//展示用户信息的View
public class MvvmMainActivity extends AbstractBaseMvvmActivity<MvvmActivityMainBinding, VMUser> implements View.OnClickListener {
@Override
protected int getContentViewId() {
return R.layout.mvvm_activity_main;
}
@Override
protected Class<VMUser> getVmClass() {
return VMUser.class;
}
@Override
protected void init() {
getViewModel().getUserInfo().setValue(UserBean.UserBeanBuilder.newBuilder().setName("live data init").setAge("0").build());
//设置绑定数据
getBinding().setVMUser(getViewModel());
//添加点击事件
getBinding().setEventListener(this);
// //live data 的数据监听
// getViewModel().getUserInfo().observe(this, new Observer() {
// @Override
// public void onChanged(UserBean userBean) {
// Toast.makeText(MvvmMainActivity.this, userBean.getName(), Toast.LENGTH_SHORT).show();
// }
// });
}
@Override
public void onClick(View view) {
LogUtils.e("haaoaha");
if (view.getId() == R.id.title) {
//点击加载用户数据
getViewModel().loadUserInfo();
}
}
}
数据动态绑定的 mvvm_activity_main.xml
<?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">
<data>
<variable
name="userNoLive"
type="com.lyldding.modulemvvm.bean.UserNoLiveBean" />
<!--用户数据绑定-->
<variable
name="vMUser"
type="com.lyldding.modulemvvm.viewmodel.VMUser" />
<!--点击事件绑定-->
<variable
name="eventListener"
type="com.lyldding.modulemvvm.MvvmMainActivity" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/title"
style="@style/Text_Style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{eventListener::onClick}"
android:text="获取用户信息"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!-- data binding 示例-->
<TextView
android:id="@+id/name_no_live"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="50dp"
android:text="@{userNoLive.name}"
app:layout_constraintBottom_toTopOf="@id/age_no_live"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/age_no_live"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="50dp"
android:text="@{userNoLive.age}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@id/title" />
<!--live data 示例-->
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@{vMUser.userInfo.name}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/title" />
<TextView
android:id="@+id/age"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@{vMUser.userInfo.age}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/name" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>