DataBinding
android UI 控件从xml文件的对象化存在大量的重复操作,相信每一个android开发者都经历过findViewById的阶段。
直到注解被重视后,通过注解省略findViewById这个流程变得简单了,我们最初是通过反射加注解在编译期完成注册,看上很像是ButterKnife
ButterKnife为了适配更多的场景,不仅仅使用了注解,还有注解处理器(annotationProcess)类似 APT(Annotation Processing Tool), 手机玩目标类基本信息后,再用JavaPoet生成Java类文件。
而我今天想说的DataBinding则给了Android开发者另外一种独特的体验:
1.如果你写过Js项目,想必双向绑定的印象肯定会特别深刻,而databinding在xml文件中的使用方式,将会让你更深刻
<data>
<import type="com.google.samples.apps.sunflower.data.Plant"/>
<variable
name="viewModel"
type="com.google.samples.apps.sunflower.viewmodels.PlantDetailViewModel" />
<variable
name="callback"
type="com.google.samples.apps.sunflower.PlantDetailFragment.Callback" />
</data>
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorSurface"
app:statusBarScrim="?attr/colorSurface"
app:collapsedTitleGravity="center"
app:collapsedTitleTextAppearance="@style/TextAppearance.Sunflower.Toolbar.Text"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:title="@{viewModel.plant.name}" // viewModel的这样使用是不是很特别
app:titleEnabled="false"
app:toolbarId="@id/toolbar">
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
style="@style/Widget.MaterialComponents.FloatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/fab_margin"
android:onClick="@{() -> callback.add(viewModel.plant)}" // 甚至我的天 方法回调也能实现
android:tint="@android:color/white"
app:shapeAppearance="@style/ShapeAppearance.Sunflower.FAB"
app:isFabGone="@{viewModel.isPlanted}"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|end"
app:srcCompat="@drawable/ic_plus" />
2.上面那个例子可以让你惊讶它的双向绑定的能力,而下面则是释放双手
// RegisterActivity.java 实现注册功能
public class RegisterActivity extends MVVMActivity {
private final static String TAG = "RegisterActivity";
ActivityRegisterBinding mDataBinding;
RegisterViewModel mViewModel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void initViewModel() {
mDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_register);
}
@Override
public void init(){
mLoading = new LoadingDialog.Builder(RegisterActivity.this);
mLoading.setMessage(getString(R.string.register_loading));
mLoading.create();
}
@Override
public void bindUi(){
// 点击上方关闭按钮
RxView.clicks(mDataBinding.closeImg)
.to(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(this)))
.subscribe(unit -> finish());
// 点击注册按钮
RxView.clicks(mDataBinding.submitBtn)
.to(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(this)))
.subscribe(unit -> mViewModel.register(mDataBinding.registerUserNameEdt.getText().toString().trim()
, mDataBinding.registerPasswordEdt.getText().toString().trim()
, mDataBinding.repeatRegisterPasswordEdt.getText().toString().trim()));
}
@Override
public void subscribeUi() {
// 注册页面状态更变通知
mViewModel.getRegisterState().observe(this, state -> {
switch (state) {
case ERROR_CUSTOMER_SUCCESS_PASS:
mLoading.getObj().show(); // 通过校验 开始网络请求
break;
case ERROR_CUSTOMER_PASSWORD_ERROR: // 账号错误
case ERROR_CUSTOMER_USERNAME_ERROR: // 密码错误
case ERROR_CUSTOMER_REPEAT_ERROR: // 账号密码不一致
ToastUtil.showToast(this, TCErrorConstants.getErrorInfo(state));
break;
}
});
// 注册接口回调通知
LiveEventBus.get(RequestTags.REGISTER_REQ, BaseResponBean.class)
.observe(this, bean -> {
Optional.ofNullable(mLoading).ifPresent(builder -> mLoading.getObj().dismiss()); // 取消 Loading
if (bean != null && bean.getCode() == 200) { // 注册成功 就开始自动登录
ToastUtil.showToast(RegisterActivity.this, "注册成功!");
mLoading.setMessage(getString(R.string.login_loading_text)).create().show(); // 显示登录中的loading
mViewModel.login(mDataBinding.registerUserNameEdt.getText().toString().trim() // 注册成功后 进行登录请求
, mDataBinding.registerPasswordEdt.getText().toString().trim());
} else {
ToastUtil.showToast(RegisterActivity.this, "注册失败:" + TCErrorConstants.getErrorInfo(bean.getCode()));
}
});
// 登录接口回调通知
LiveEventBus.get(RequestTags.LOGIN_REQ, BaseResponBean.class)
.observe(this, bean -> {
if (bean == null) return;
Optional.ofNullable(mLoading).ifPresent(builder -> mLoading.getObj().dismiss()); // 取消 Loading
if (bean.getCode() == 200) { // 登录成功
ToastUtil.showToast(this, "登录成功!");
startActivity(new Intent(RegisterActivity.this, MainActivity.class));
finish();
} else { // 登录失败
ToastUtil.showToast(this, "登录失败:" + TCErrorConstants.getErrorInfo(bean.getCode()));
}
});
}
@Override
public void initRequest() {
}
@Override
protected void onDestroy() {
super.onDestroy();
Optional.ofNullable(mLoading).ifPresent(builder -> mLoading.getObj().dismiss()); // 取消 Loading
}
}
上面是我用DataBinding + ViewModel + LiveData + LiveDataBus + RxView 实现的一个注册功能
3.DataBinding在Adapter中的使用呢
// MessageAdapter.java
public class MessageAdapter extends BaseQuickAdapter<MessageItemBean, BaseDataBindingHolder<LayoutMessageSignBinding>> {
Context context;
public MessageAdapter(Context context, int layoutResId, @Nullable List<MessageItemBean> data) {
super(layoutResId, data);
this.context = context;
}
@Override
protected void convert(@NotNull BaseDataBindingHolder<LayoutMessageSignBinding> layoutMessageSignBindingBaseDataBindingHolder, MessageItemBean messageItemBean) {
LayoutMessageSignBinding binding = DataBindingUtil.getBinding(layoutMessageSignBindingBaseDataBindingHolder.itemView);
if(binding == null || messageItemBean == null) return;
binding.titleTv.setText(messageItemBean.getMessageTitle());
binding.timeTv.setText(messageItemBean.getMessageTime());
binding.messageContent.setText(messageItemBean.getMessageContent());
}
}
上面是DataBinding + Bravh ,让Adapter变得无比简洁
4.这里说一下databinding的原理吧
首先,databinding会把xml拆分成数据和布局两部分 剩下的明天继续
网友评论