Data Binding 初体验
简单使用
用于 Data-bindng 的模板文件,是由 data 节点 跟 layout 节点组成.
一个简单的示例如下:
<?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>
使用上来说,如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityDataBindingBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_data_binding);
binding.setUser( new User("Haizhen","Lee"));
}
然后就OK了, 以前繁杂的findViewById的调用,及设置值
与RecyclerView 结合使用示例
与普通的 ViewHolder有所区别, 保存一个 Binding应该是比较好的选择:
class UserViewHolder extends RecyclerView.ViewHolder {
private RecyclerListItemBinding mBinding;
public UserViewHolder(RecyclerListItemBinding binding) {
super(binding.getRoot());
mBinding = binding;
}
public void bind(User user){
mBinding.setUser(user);
}
}
然后修改RecyclerViewAdapter如下:
class DemoRecyclerViewAdapter extends RecyclerView.Adapter<UserViewHolder>{
private List<User> userList;
private static final int layoutId = R.layout.recycler_list_item;
public DemoRecyclerViewAdapter(List<User> users){
this.userList = users;
}
@Override
public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
RecyclerListItemBinding binding = DataBindingUtil.inflate(layoutInflater,layoutId,parent,false);
return new UserViewHolder(binding);
}
@Override
public void onBindViewHolder(UserViewHolder holder, int position) {
User user = userList.get(position);
holder.bind(user);
}
@Override
public int getItemCount() {
return userList.size();
}
}
好奇的心
ActvityDataBindingBinding 怎么来的?
这是 Android 编译系统 根据布局文件名activity_data_binding.xml生成的
是编译期动态生成类DataBindingUtil 做了什么?
查看源代码如下:
public static <T extends ViewDataBinding> T setContentView(Activity activity, int layoutId) {
View decorView = activity.getWindow().getDecorView();
ViewGroup contentView = (ViewGroup)decorView.findViewById(16908290);
ViewDataBinding binding = inflate(activity.getLayoutInflater(), layoutId, contentView, false);
activity.setContentView(binding.getRoot(), binding.getRoot().getLayoutParams());
return binding;
}
看看ActivityDataBindingBinding 怎么绑定的.
可以看到绑定User对象的操作在 executeBindings中进行.
@Override
protected void executeBindings() {
long dirtyFlags = 0;
synchronized(this) {
dirtyFlags = mDirtyFlags;
mDirtyFlags = 0;
}
java.lang.String firstNameUser = null;
java.lang.String lastNameUser = null;
com.banxi1988.v2exgeek.demo.User user = mUser;
if ((dirtyFlags & 0b11L) != 0) {
// read firstName~.~user~
if ( user != null) {
firstNameUser = user.firstName;
}
// read lastName~.~user~
if ( user != null) {
lastNameUser = user.lastName;
}
}
// batch finished
if ((dirtyFlags & 0b11L) != 0) {
// api target 1
this.mboundView1.setText(firstNameUser);
}
if ((dirtyFlags & 0b11L) != 0) {
// api target 1
this.mboundView2.setText(lastNameUser);
}
}
新布局文件编译后的中间产物
在build/layout-info/debug 目录下生成的如下内容的
文件,名为:activity_data_bindingLayout.xml文件中
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Layout layout="activity_data_binding"
modulePackage="com.banxi1988.v2exgeek"
directory="layout"
isMerge="false">
<Variables>
<entries type="com.banxi1988.v2exgeek.demo.User" name="user"/>
</Variables>
<Targets>
<Target tag="layout/activity_data_binding_0" view="LinearLayout">
<Expressions/>
</Target>
<Target tag="binding_1" view="TextView">
<Expressions>
<Expression text="user.firstName" attribute="android:text"/>
</Expressions>
</Target>
<Target tag="binding_2" view="TextView">
<Expressions>
<Expression text="user.lastName" attribute="android:text"/>
</Expressions>
</Target>
</Targets>
</Layout>
多一些了解
- 类的生成使用了
antlr库 - 对 null 宽容, 也提供了
??操作符,方便的为null的引用设置默认值 想起了 AngularJS, 以前的 JSP, 但是说绑定肯定不如AngularJS.
不过对于 Android 开发者来说,也已经是极大的进步了.在xml的属性中写表达式, 要用到小于号大于号的都觉得挺悲剧的,希望正式版本能有更好的写法
android:visibility="@{age < 13 ? View.GONE : View.VISIBLE}"
<variable name="userList" type="List<User>"/>
编译期的元编程
- data binding 选择 在编译期来做 View 查找定位,生成数据绑定代码, 这样保证了性能.
- 以前使用过 ButterKnife 就觉得非常好用,data binding 进一步增加了好用程度. 不过他们都有一个特点就是,充分利用了编译期动态生成代码, ButterKnife 对 annotation processing 的依赖也更强一些. 另一个有名依赖注入库,Dagger 也是充分利用了注解在编译期生成代码. 这样为了编程的编程,这就是我心中的元编程.
- 希望有更多基于Java注解,基于编译期代码生成的工具,库出来,造福广大开发者