Data Binding Library
Data Binding Library有很强的灵活性和广泛的兼容性——它是一个支持库(support library),支持Android 2.1以上版本 (API level 7+),Gradle 版本为1.5.0-alpha1以上,Android Studio版本为 1.3以上。
配置环境(Build Environment)
在app的build.gradle中添加 data binding 元素。
android {
....
dataBinding {
enabled = true
}
}
另外,如果你想要添加其他依赖了 data binding 的库的话也要先在gradle文件中配置 data binding 环境后使用。
绑定数据和布局文件(Data Binding Layout Files)
布局文件中的设置
起始根标签是 layout,接下来一个 data 元素以及一个 view 的根元素。这个view元素就是显示的界面布局。
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="user" type="com.example.User"/> </data> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.firstName}"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.lastName}"/> </LinearLayout> </layout>
data 标签中 variable 条目的 type 属性值为导入的可能被绑定的变量对象,在控件中使用此对象中变量绑定的方式为:android:text=”@{user.lastName}”,@{}表示调用,括号里面为绑定的对象变量。
绑定对象的创建(Data Object)
被绑定的对象结构 :
public class { public final String firstName; public final String lastName; public (String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } // getXXX形式 public String getFirstName { return firstName; } }
也可以使用属性名方法名相同的形式
public class { private final String firstName; private final String lastName; public (String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } // 或者属性名和方法名相同 public String lastName { return lastName; } }
在界面中显示被绑定的数据(Binding Data)
在布局文件中添加完data标签后,Android Studio就会根据xml的文件名自动生成一个继承ViewDataBinding的类。例如: main_activity.xml 就会生成 MainActivityBinding , 然后我们在Activity里面添加如下代码:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity); User user = new User("Test", "User"); binding.setUser(user); }
然后运行!会看到绑定对象中的变量数据已经可以显示在布局中了!
在没有使用DataBinding的布局中,设置需要显示的布局文件方法一般为setContentView(@LayoutRes int layoutResID),而使用DataBinding之后的设置显示布局方法可以使用DataBinUtil中的setContentView,同时也会获得到继承ViewDataBinding的类MainActivityBinding。
如果只是要生成 View 对象而不显示到 Activity 上,那么应该用以下的代码:
MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflater());
如果想要获得ListView 或者 RecyclerView adapter中的items的view,那么可以用下面的代码获得:
ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false); //或者 ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);
得到binding后可以直接调用被绑定的控件获得 View 对象,如:
//布局文件中控件id为tv_firstName android:id="@+id/tv_firstName"
元素名为id去掉下划线并使其符合变量的命名规则tvFirstName
//代码中获得控件view TextView tvFirstName = binding.tvFirstName;
绑定方法和事件(Event Handling)
绑定方法和事件,有两种方式进行绑定。
Method References:
- 和我们将Button的onclick点击事件方法直接绑定到Activity中类似,我们可以使用Data Binding将绑定对象中的方法与某个控件的事件绑定。在绑定过程中需注意如果方法不存在或者签名不正确会编译报错。
以Button的onclick点击事件为例:
//绑定对象 public class MyHandlers { public void onClickFriend(View view) { ... } }
在布局文件中设置绑定方法onClickFriend
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="handlers" type="com.example.Handlers"/> <variable name="user" type="com.example.User"/> </data> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.firstName}" android:onClick="@{handlers.onClickFriend}"/> </LinearLayout> </layout>
与Listener Bindings方式绑定之间最主要的不同为Method References的listener在数据绑定的同时已经建立,而Listener Bindings的listener则是在APP运行后,事件触发时才建立。如果需要在控件的事件触发时进行对其他情况判断处理,则建议选用Listener Bindings的方式进行绑定。
Listener Bindings:
- Listener Bindings是当事件触发时在建立监听的绑定方式,和Method References类似,并且可以在事件触发时进行事件处理。Gradle版本要求2.0或以上,并且使用的是lambda表达式。
- 在Method References方式中,被绑定的方法传递参数必须和控件的listener的参数类型一样才可以使用,但是在Listener Bindings中只要被绑定的方法和控件listener方法最后返回的参数类型一样就OK了,感觉比Method References方式灵活了许多。
还是以Button的onclick点击事件为例:
//绑定对象 public class Presenter { public void onSaveClick(Task task){} }
在布局文件中设置绑定方法onSaveClick
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="task" type="com.android.example.Task" /> <variable name="presenter" type="com.android.example.Presenter" /> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="@{() -> presenter.onSaveClick(task)}" /> </LinearLayout> </layout
以上布局在绑定方法时的代码为@{() -> presenter.onSaveClick(task)},其中对于listener的事件方法参数都没有描述,则表示的是默认的方法,在以上代码中方法是onClick(View v),Listener Bindings方式对于listener的触发事件参数的描述有两种方式,除了以上例子中一个参数都不声明外,两外一种方式就是每个参数都声明:
android:onClick="@{(view) -> presenter.onSaveClick(task)}"
你也可以在绑定的方法中引用Listener传递的参数:
//绑定对象代码 public class Presenter { public void onSaveClick(View view, Task task){} } //布局文件中的绑定 android:onClick="@{(theView) -> presenter.onSaveClick(theView, task)}"
也可以使用lambda表达式声明描述多个listener的触发事件参数:
//绑定对象代码 public class Presenter { public void onCompletedChanged(Task task, boolean completed){} } //布局文件中的绑定 <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content" android:onCheckedChanged="@{(cb, isChecked) -> presenter.completeChanged(task, isChecked)}" />
绑定对象中的方法和你绑定的这个listener中方法返回值的类型必须一样,比如长按事件onLongClick:
//绑定对象代码 public class Presenter { public boolean onLongClick(View view, Task task){} } //布局文件中的绑定 android:onLongClick="@{(theView) -> presenter.onLongClick(theView, task)}"
返回值如果为空null,则和定义变量默认情况相同,如int类型默认返回0,boolean类型默认返回false,等等
当使用断言时,可以将void当做变量使用。
android:onClick="@{(v) -> v.isVisible() ? doSomething() : void}"