如果想要使用Databinding来实现MVVM的架构,这篇文章将会教会你实现的具体流程:
一、首先需要在app.build里面的android层级下添加dataBinding配置
android {
dataBinding {
enabled = true
}
}
二、在xml中添加databinding的代码,与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>
<variable
name="anchorBindingViewModel"
type="com.cdtye.emergencyDirection.viewmodel.MaoDuanEnrollmentViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="vertical"
tools:context=".view.activity.BdLabelBindingActivity">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:fillViewport="true"
android:scrollbars="none">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@color/white"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:paddingLeft="10dp"
android:background="@color/colorBackground"
android:textColor="@color/success_stroke_color"
android:textSize="13sp"
android:text="基本信息"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/ll_height1"
android:layout_marginLeft="@dimen/width_4"
android:layout_marginRight="@dimen/width_4"
android:layout_marginTop="@dimen/width_2"
android:layout_marginBottom="@dimen/width_1"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="锚段编号"
android:textColor="@color/black"
android:textSize="@dimen/sp_14" />
<EditText
android:id="@+id/et_anchor_no"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="@dimen/ll_height1"
android:background="@null"
android:gravity="right"
android:hint="@string/please_set"
android:inputType="text"
android:textColor="@color/text_color2"
android:textColorHint="@color/text_color3"
android:textSize="@dimen/text_small_20" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/width_2"
android:layout_gravity="center"
android:visibility="invisible"
android:src="@mipmap/down"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="@dimen/width_line"
android:layout_marginLeft="@dimen/width_4"
android:layout_marginRight="@dimen/width_4"
android:background="@color/line"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/ll_height1"
android:layout_marginLeft="@dimen/width_4"
android:layout_marginRight="@dimen/width_4"
android:layout_marginTop="@dimen/width_2"
android:layout_marginBottom="@dimen/width_1"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="锚段长度"
android:textColor="@color/black"
android:textSize="@dimen/sp_14" />
<EditText
android:id="@+id/et_anchor_length"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="@dimen/ll_height1"
android:background="@null"
android:gravity="right"
android:hint="@string/please_set"
android:inputType="numberDecimal"
android:textColor="@color/text_color2"
android:textColorHint="@color/text_color3"
android:textSize="@dimen/text_small_20" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/width_2"
android:layout_gravity="center"
android:visibility="invisible"
android:src="@mipmap/down"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="@dimen/width_line"
android:layout_marginLeft="@dimen/width_4"
android:layout_marginRight="@dimen/width_4"
android:background="@color/line"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="@dimen/width_2"
android:layout_marginBottom="4dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="@color/black"
android:textSize="@dimen/sp_14"
android:text="线路"/>
<TextView
android:id="@+id/tv_line"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center|right"
android:hint="请选择"
android:text="@{anchorBindingViewModel.lineName}"
android:textColorHint="@color/text_color3"
android:textColor="@color/text_color"
android:textSize="@dimen/sp_14" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_gravity="center"
android:visibility="visible"
android:src="@mipmap/down"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="@dimen/width_line"
android:layout_marginLeft="@dimen/width_4"
android:layout_marginRight="@dimen/width_4"
android:background="@color/line"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/ll_height1"
android:layout_marginLeft="@dimen/width_4"
android:layout_marginRight="@dimen/width_4"
android:layout_marginTop="@dimen/width_2"
android:layout_marginBottom="@dimen/width_1"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="部门"
android:textColor="@color/black"
android:textSize="@dimen/sp_14" />
<TextView
android:id="@+id/tv_bm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:textColorHint="@color/text_color3"
android:gravity="right"
android:hint="请选择"
android:textColor="@color/text_color"
android:textSize="@dimen/sp_14" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/width_2"
android:layout_gravity="center"
android:visibility="visible"
android:src="@mipmap/down"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="@dimen/width_line"
android:layout_marginLeft="@dimen/width_4"
android:layout_marginRight="@dimen/width_4"
android:background="@color/line"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/ll_height1"
android:layout_marginLeft="@dimen/width_4"
android:layout_marginRight="@dimen/width_4"
android:layout_marginTop="@dimen/width_2"
android:layout_marginBottom="@dimen/width_1"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="@color/black"
android:textSize="@dimen/sp_14"
android:text="开始区间站场"/>
<TextView
android:id="@+id/tv_start_district_station"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center|right"
android:hint="请选择"
android:text="@{anchorBindingViewModel.startStationBean.siteName}"
android:textColorHint="@color/text_color3"
android:textColor="@color/text_color"
android:textSize="@dimen/sp_14" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/width_2"
android:layout_gravity="center"
android:visibility="visible"
android:src="@mipmap/down"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="@dimen/width_line"
android:layout_marginLeft="@dimen/width_4"
android:layout_marginRight="@dimen/width_4"
android:background="@color/line"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/ll_height1"
android:layout_marginLeft="@dimen/width_4"
android:layout_marginRight="@dimen/width_4"
android:layout_marginTop="@dimen/width_2"
android:layout_marginBottom="@dimen/width_1"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="@color/black"
android:textSize="@dimen/sp_14"
android:text="结束区间站场"/>
<TextView
android:id="@+id/tv_end_district_station"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center|right"
android:hint="请选择"
android:text="@{anchorBindingViewModel.endStationBean.siteName}"
android:textColorHint="@color/text_color3"
android:textColor="@color/text_color"
android:textSize="@dimen/sp_14" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/width_2"
android:layout_gravity="center"
android:visibility="visible"
android:src="@mipmap/down"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="@dimen/width_line"
android:layout_marginLeft="@dimen/width_4"
android:layout_marginRight="@dimen/width_4"
android:background="@color/line"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/ll_height1"
android:layout_marginLeft="@dimen/width_4"
android:layout_marginRight="@dimen/width_4"
android:layout_marginTop="@dimen/width_2"
android:layout_marginBottom="@dimen/width_1"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="@color/black"
android:textSize="@dimen/sp_14"
android:text="行别"/>
<TextView
android:id="@+id/tv_xingb"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center|right"
android:text="@{anchorBindingViewModel.directionName}"
android:hint="请选择"
android:textColorHint="@color/text_color3"
android:textColor="@color/text_color"
android:textSize="@dimen/sp_14" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/width_2"
android:layout_gravity="center"
android:src="@mipmap/down"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="@dimen/width_line"
android:layout_marginLeft="@dimen/width_4"
android:layout_marginRight="@dimen/width_4"
android:background="@color/line"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/ll_height1"
android:layout_marginLeft="@dimen/width_4"
android:layout_marginRight="@dimen/width_4"
android:layout_marginTop="@dimen/width_2"
android:layout_marginBottom="@dimen/width_1"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="开始公里标"
android:textColor="@color/black"
android:textSize="@dimen/sp_14" />
<EditText
android:id="@+id/tv_start_km_mark"
android:layout_width="0dp"
android:background="@color/transparent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:hint="K0000+000"
android:textColorHint="@color/gray1"
android:gravity="right"
android:textColor="@color/text_color"
android:textSize="@dimen/sp_14" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/width_2"
android:layout_gravity="center"
android:visibility="invisible"
android:src="@mipmap/down"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="@dimen/width_line"
android:layout_marginLeft="@dimen/width_4"
android:layout_marginRight="@dimen/width_4"
android:background="@color/line"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/ll_height1"
android:layout_marginLeft="@dimen/width_4"
android:layout_marginRight="@dimen/width_4"
android:layout_marginTop="@dimen/width_2"
android:layout_marginBottom="@dimen/width_1"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="结束公里标"
android:textColor="@color/black"
android:textSize="@dimen/sp_14" />
<EditText
android:id="@+id/tv_end_km_mark"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/transparent"
android:layout_gravity="center"
android:layout_weight="1"
android:hint="K0000+000"
android:textColorHint="@color/gray1"
android:gravity="right"
android:textColor="@color/text_color"
android:textSize="@dimen/sp_14" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/width_2"
android:layout_gravity="center"
android:visibility="invisible"
android:src="@mipmap/down"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="@dimen/width_line"
android:layout_marginLeft="@dimen/width_4"
android:layout_marginRight="@dimen/width_4"
android:background="@color/line"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/ll_height1"
android:layout_marginLeft="@dimen/width_4"
android:layout_marginRight="@dimen/width_4"
android:layout_marginTop="@dimen/width_2"
android:layout_marginBottom="@dimen/width_1"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="支柱坐标"
android:textColor="@color/black"
android:textSize="@dimen/sp_14" />
<TextView
android:id="@+id/tv_gps"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:text="请进行定位"
android:gravity="right"
android:textColor="@color/text_color"
android:textSize="@dimen/sp_14" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/width_2"
android:layout_gravity="center"
android:visibility="visible"
android:src="@mipmap/down"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="@dimen/width_line"
android:layout_marginLeft="@dimen/width_4"
android:layout_marginRight="@dimen/width_4"
android:background="@color/line"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/ll_height1"
android:layout_marginLeft="@dimen/width_4"
android:layout_marginRight="@dimen/width_4"
android:layout_marginTop="@dimen/width_2"
android:layout_marginBottom="@dimen/width_1"
android:visibility="gone"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="@color/black"
android:textSize="@dimen/sp_14"
android:text="设备编码"/>
<TextView
android:id="@+id/tv_devnum"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="right"
android:textColor="@color/text_color"
android:textSize="@dimen/sp_14" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/width_2"
android:layout_gravity="center"
android:visibility="invisible"
android:src="@mipmap/down"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="@dimen/width_line"
android:layout_marginLeft="@dimen/width_4"
android:layout_marginRight="@dimen/width_4"
android:visibility="gone"
android:background="@color/line"/>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="20dp"
android:orientation="horizontal">
<Button
android:id="@+id/btn_save_and_continue"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:visibility="gone"
android:background="@drawable/blue_stroke_button_background"
android:gravity="center"
android:text="保存继续" />
<Button
android:id="@+id/btn_save"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/blue_stroke_button_background"
android:gravity="center"
android:text="保存" />
<Button
android:id="@+id/btn_close"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_weight="1"
android:gravity="center"
android:background="@drawable/blue_button_background"
android:textColor="@color/white"
android:textSize="15sp"
android:text="关闭" />
</LinearLayout>
</LinearLayout>
</layout>
接下来就需要搭建ViewModel
public class MaoDuanEnrollmentViewModel extends DeviceEnrollmentViewModel {
public static final String TAG = MaoDuanEnrollmentViewModel.class.getName();
public LiveDataEvent<String> lineName = new LiveDataEvent<>();
/**
* 站点
*/
public LiveDataEvent<List<AnchorSiteBean>> queryStartSeclineSiteListEvent = new LiveDataEvent<>();
public LiveDataEvent<List<AnchorSiteBean>> queryEndSeclineSiteListEvent = new LiveDataEvent<>();
public LiveDataEvent<AnchorSiteBean> startStationBean = new LiveDataEvent<>();
public LiveDataEvent<AnchorSiteBean> endStationBean = new LiveDataEvent<>();
public LiveDataEvent<List<DirectionBean>> queryDirectionListEvent = new LiveDataEvent<>();
/**
* 保存成功
*/
public LiveDataEvent<JCWAnchorBean> saveSuccessEvent = new LiveDataEvent<>();
/**
* 行别名称
*/
public LiveDataEvent<String> directionName = new LiveDataEvent<>();
//这里是一些网络请求的方法
public void getJcwDirectionList(){
}
public void saveAnchorData(JCWAnchorBean jcwAnchorBean) {
addSubscribe(useCase.uploadJcwAnchorInfo(jcwAnchorBean).subscribe(list -> {
LogUtils.d(TAG, "saveSuccess");
//保存成功,将保存的数据给到saveSuccessEvent
saveSuccessEvent.call(jcwAnchorBean);
//伪代码,模拟获取到的数据实时更新UI
viewModel.directionName.setValue(direction.getDirectionName());
}, throwable -> {
LogUtils.e(TAG, throwable);
}));
}
}
addSubscribe是使用Rxjava进行集中的请求处理
protected void addSubscribe(Disposable disposable) {
if (compositeDisposable == null) {
compositeDisposable = new CompositeDisposable();
}
compositeDisposable.add(disposable);
}
LiveDataEvent是一个封装好的MutableLiveData,可以监听任意类型数据
public class LiveDataEvent<T> extends MutableLiveData<T> {
private static final String TAG = LiveDataEvent.class.getName();
private long lastEventSendTime = 0;
private AtomicBoolean atomicBoolean = new AtomicBoolean(false);
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
if (hasActiveObservers()) {
Log.e(TAG, "只能有一个事件 notified");
}
super.observe(owner, t -> {
if (atomicBoolean.compareAndSet(true, false)) {
observer.onChanged(t);
}
});
}
@MainThread
private void setDataValue(@Nullable T t) {
atomicBoolean.set(true);
super.setValue(t);
}
@MainThread
public void call(T t) {
setDataValue(t);
}
/**
* 触发事件
*
* @param t 泛型,需要发送的数据
* @param limitEventSend 是否限制事件的发出,比如规定1秒内不能发出两个事件,防止多次点击按钮
*/
@MainThread
public void call(T t, boolean limitEventSend) {
if (limitEventSend) {
//必须超过规定的时间才能发出事件
if (!isFastClick()) {
setDataValue(t);
}
} else {
setDataValue(t);
}
}
/**
* 事件需要规定的事件才能发出,比如防止点击过快
*
* @return true-小于规定时间
*/
public boolean isFastClick() {
boolean flag = true;
long currentClickTime = System.currentTimeMillis();
if ((currentClickTime - lastEventSendTime) >= Config.INTERVAL_CLICK_TIME) {
flag = false;
}
lastEventSendTime = currentClickTime;
return flag;
}
}
三、在baseActivity中要做的事情:
public abstract class BaseActivity<T extends ViewDataBinding, E extends BaseViewModel> extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int layoutRes = getLayout();
if (layoutRes > 0) {
//如果不使用MVVM设计模式,则实现IBase接口的useMvvm()方法,并且返回false
if (useMvvm()) {
binding = DataBindingUtil.setContentView(this, layoutRes);
initViewModel();
} else {
setContentView(layoutRes);
}
}
}
protected void initViewModel() {
int variableId = getVariableId();
viewModel = bindViewModel();
if (viewModel == null) {
return;
}
//订阅事件
observerEvent();
viewModel.attachView(this, this);
//xml 关联ViewModel
binding.setVariable(variableId, viewModel);
//支持LiveData绑定xml,数据动态刷新
binding.setLifecycleOwner(this);
//让ViewModel拥有View的生命周期感应
getLifecycle().addObserver(viewModel);
}
protected abstract int getLayout();
/**
* 获取ViewModel id
*/
@Override
public int getVariableId() {
return -1;
}
/**
* Binding ViewModel instance to ViewDataBinding
*/
@Override
public E bindViewModel() {
return null;
}
@Override
public void observerEvent() {
viewModel.backEvent.observe(this, s -> goBack());
}
@Override
public void goBack() {
finish();
}
}
四、具体xml对应的activity
public class MaoDuanEnrollmentActivity extends DeviceEnrollmentActivity<ActivityMaoduanEnrollmentBindingBinding, MaoDuanEnrollmentViewModel>{
private static final String TAG = MaoDuanEnrollmentActivity.class.getName();
private JCWAnchorBean jcwKeyDevBeanAfterSuccess;
@Override
public int getVariableId() {
return BR.anchorBindingViewModel;
}
@Override
protected int getLayout() {
return R.layout.activity_maoduan_enrollment_binding;
}
@Override
public MaoDuanEnrollmentViewModel bindViewModel() {
return new MaoDuanEnrollmentViewModel();
}
@Override
public void observerEvent() {
super.observerEvent();
viewModel.saveSuccessEvent.observe(this, jcwAnchorBean -> {
jcwKeyDevBeanAfterSuccess = jcwAnchorBean;
if (binding.btnSaveAndContinue.getVisibility() != View.VISIBLE) {
binding.btnSaveAndContinue.setVisibility(View.VISIBLE);
binding.btnSave.setVisibility(View.GONE);
}
});
}
}
后续事件的监听只需要放在obserEvent方法中即可
优点与缺点:
MVVM相比于MVP的优势:相对于MVP更一步的解耦了,用户只需要进行UI的修改而无需关心数据的来源,ViewModel中主要获取数据并给到Activity,Activity根据Data进行相应的业务操作,减轻了Activity的负重。
缺点:ViewModel中比较臃肿,数据请求,数据解析都集中在这里边,且每一个需要获取数据展示的视图都需要一个LiveDataEvent进行监听,若xml中需要实时更新数据的UI较多,ViewModel的责任比较大。