通常情况下Jetpack组件都是混合一起使用的,这里我们为了讲解,可能会单独使用。
前一篇中我们讲解了ViewModel,终于要介绍大Boos组件DataBinding。
DataBinding是Android上MVVM实现最强大的组件,是 MVVM 模式在 Android 上的一种实现,用于降低布局和逻辑的耦合性,使代码逻辑更加清晰。DataBinding 能够省去我们一直以来的 findViewById() 步骤,大量减少 Activity 内的代码,数据能够单向或双向绑定到 layout。
来看一下怎么使用
在build.gradle
中添加对Databinding的支持。
android {
...
dataBinding {
enabled = true
}
}
打开布局文件,选中根布局,按住 Alt + 回车键,点击 “Convert to data binding layout”,就可以生成 DataBinding 需要的布局规则。
<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>
<import type="cn.iwcode.androidjetpack.databind1.UserBean" />
<variable
name="userInfo"
type="UserBean" />
data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".databind1.DataBindActivity1">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{userInfo.name}"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{userInfo.phoneNUmber}"/>
LinearLayout>
layout>
layout 标签将原布局包裹了起来,data 标签用于声明要用到的变量以及变量类型。
每个绑定的布局都会生成一个绑定类,ViewDataBinding 的实例名是根据布局文件名来生成,将之改为首字母大写的驼峰命名法来命名,并省略布局文件名包含的下划线。控件的获取方式类似,但首字母小写。
也可以通过class
自定义ViewDataBinding实例名
<data class="CustomBinding">
data>
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_data_bind_1);
ActivityDataBind1Binding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_data_bind_1);
UserBean userBean = new UserBean();
userBean.name = "ygs";
userBean.phoneNUmber = "18612345678";
viewDataBinding.setUserInfo(userBean);
}
简单的Model绑定后,如果数据改变并不会让UI自动更新,而我们希望数据改变时,实时刷新UI。
实现数据变化自动驱动 UI 刷新的方式有三种:BaseObservable、ObservableField、ObservableCollection
BaseObservable有 notifyChange() 和 notifyPropertyChanged() 两个方法刷新数据,
public class UserBean extends BaseObservable {
//如果是 public 修饰符,则可以直接在成员变量上方加上 @Bindable 注解
//如果是 private 修饰符,则在成员变量的 get 方法上添加 @Bindable 注解
@Bindable
public String name;
public String phoneNUmber;
public int age;
//更新所有的字段
public void setAll(String name, String phoneNUmber, int age) {
this.name = name;
this.phoneNUmber = phoneNUmber;
this.age = age;
notifyChange();
}
// 只更新name字段
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
public void setPhoneNUmber(String phoneNUmber) {
this.phoneNUmber = phoneNUmber;
}
}
在调用setName方法是只更新name字段,而setAll会更新所有的字段。
手动去调用notifyPropertyChanged太麻烦,官方提供了ObservableField包装类。
ObservableField是对 BaseObservable 中字段的注解和刷新等操作的封装,官方原生提供了对基本数据类型的封装,例如 ObservableBoolean、ObservableByte、ObservableChar、ObservableShort、ObservableInt、ObservableLong、ObservableFloat、ObservableDouble 以及 ObservableParcelable ,也可通过 ObservableField 泛型来申明其他类型。
public class UserBean extends BaseObservable {
public ObservableField<String> name;
public ObservableField<String> phoneNUmber;
public ObservableField<Integer> age;
public void setAll(String name, String phoneNUmber,int age) {
this.name.set(name);
this.phoneNUmber.set(phoneNUmber);
this.age.set(age);
}
public void setName(String name) {
this.name.set(name);
}
}
这个主要是提供对list和map的包装,如ObservableArrayMap,ObservableArrayList。
双向绑定给单向绑定就多了一个等号android:text="@={userInfo.phoneNUmber}
,很简单吧:
我们新建一个事件的类,写几个事件的回调方法:
public class EventViewModel extends ViewModel {
public void onNameClick(UserBean user){
Logger.i(user);
}
public void onNameClick(View view){
Logger.i(view);
}
public void afterTextChanged(Editable s){
Logger.i("afterTextChanged: "+s.toString());
}
}
对应的xml
可以看见有3中写法
eventViewModel.onNameClick
eventViewModel::onNameClick
Lambda表达式 ()->eventViewModel.onNameClick(userInfo)
我们来看看databind与Recycleview的简单使用。
ActivityDataBind5Binding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_data_bind_5);
MainViewModel viewModel = ViewModelProviders.of(this).get(MainViewModel.class);
viewDataBinding.setViewModel(viewModel);
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:binding="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="cn.iwcode.androidjetpack.databind5.MainViewModel" />
<variable
name="viewModel"
type="MainViewModel" />
data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adapter="@{viewModel.adapter}"
android:layoutManage="@{viewModel.layoutManage}"/>
LinearLayout>
layout>
public class MainViewModel extends ViewModel {
private RecycleAdapter adapter ;
private ObservableArrayList<UserBean> listData = new ObservableArrayList<>();
private void loadData(){
for (int i = 0;i < 20 ; i++){
UserBean userBean = new UserBean();
userBean.name = "ygs-"+i;
userBean.phoneNUmber = "18612345678";
userBean.headUrl = "https://avatars1.githubusercontent.com/u/5112053?s=460&v=4";
userBean.des = "这是描述, 这是描述, 这是描述, 这是描述, 这是描述, 这是描述, 这是描述, 这是描述, 这是描述"+i;
listData.add(userBean);
}
}
public RecyclerView.LayoutManager layoutManage(){
return new LinearLayoutManager(APP.mContext);
}
public RecycleAdapter adapter(){
adapter = new RecycleAdapter(listData, APP.mContext);
loadData();
return adapter;
}
}
后面就不贴代码了,有兴趣可以去看一下