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.<BaseEntity<Weather>>io2main())
.as(this.<BaseEntity<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<UserBean>() {
// @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>