DataBinding学习(四)

1 自定义Binding类名称

默认情况下,Binding类的命名是基于所述layout文件的名称,用大写开头,除去下划线()以及()后的第一个字母大写,然后添加“Binding”后缀。这个类将被放置在一个模块封装包里的databinding封装包下。例如,所述layout文件contact_item.xml将生成ContactItemBinding。如果模块包是com.example.my.app,那么它将被放置在com.example.my.app.databinding。
Binding类可通过调整data元素中的class属性来重命名或放置在不同的包中。例如:

<data class="ContactItem">
    ...
</data>

在模块封装包的databinding包中会生成名为ContactItem的Binding类。如果要想让该类生成在不同的包种,你需要添加前缀.,如下:

<data class=".ContactItem">
    ...
</data>

在这个情况下,ContactItem类直接在模块包种生成。或者你可以提供整个包名:

<data class="com.example.ContactItem">
    ...
</data>

2 Include的使用

通过使用application namespace以及在属性中的Variable名字从容器layout中传递Variables到一个被包含的layout:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"//这就是application namespace(命名控件)
         xmlns:bind="http://schemas.android.com/apk/res-auto">//类似引入自定义属性
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <include layout="@layout/name"
           bind:user="@{user}"/>
       <include layout="@layout/contact"
           bind:user="@{user}"/>
   </LinearLayout>
</layout>

注意:在name.xml以及contact.xml两个layout文件中必需要有user variable


3 带ID的Views

DataBinding有效降低了代码的冗余性,省去了过去findViewById寻找控件,但如果现在需要使用相应的控件又如何处理呢?莫慌,只要在控件添加id属性,DataBinding就会为我们生成一个final变量。Binding会在View层次结构上做单一的传递,提取带ID的Views。这种机制比起某些Views使用findViewById还要快。上代码:
XML文件:

<data class="entity.CustomItem">//自定义Binding类名称
    <variable
        name="user"
        type="entity.User"/>
</data>
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv"  //添加id属性为tv
        android:layout_weight="1"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:text="@{user.firstName}"/>
</LinearLayout>

这样就会在CustomItem.java文件中生成如下的代码:

// views
public final android.widget.TextView tv;

你说你找不到这个文件?是的,我一开始也找不到,通过搜索查询文件,才发现,该文件存在的目录为:

D:\WorkSpace\AS\BindingDemo\app\build\intermediates\classes\debug\entity

而不是

D:\WorkSpace\AS\BindingDemo\app\src\main\java\entity

请仔细看下该文件的内容~
下面来它是如何替换findViewById工作的。
MainActivity代码:

private CustomItem binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
    User user = new User();
    user.firstName = "张三";
    user.lastName = "李四";
    binding.setUser(user);
    //binding.firstName.setText("ABCD");//-------(说明1)
}

@Override
public void onBackPressed() {
    binding.tv.setText("ABCD");//--------(说明2)
//super.onBackPressed();
}

说明1:UI 不更新,仍为”张三”(一般也没这么操作,刚setUser,又改变==)。这种方式获取控件在第一次设置text属性似乎先执行

binding.firstName.setText("ABCD")

而后在加载XML文件中的设置。
相比于findViewById那种方式获取控件有所不同,后者是先渲染XML文件,而后再查看text属性是否有改变。
说明2:不是第一次渲染XML,故可以实现UI更新。


4 ViewStubs

ViewStubs 跟正常的 Views 略有不同。他们开始时是不可见的,当他们要么设置为可见或被明确告知要载入时,它们通过载入另外一个 layout 取代了自己。
由于 ViewStub 基本上从 View 的层次结构上消失,在 Binding 对象的 View 也必须消失来允许被收集。因为 Views 是最后的,一个 ViewStubProxy 对象取带 ViewStub,给开发者获得了 ViewStub,当它存在以及还可以访问载入的 View 层次结构时当 ViewStub已被载入时。
当载入另一个 layout,为新的布局必需创建一个 Binding。因此, ViewStubProxy 必需监听 ViewStubOnInflateListener 监听器并在那个时候建立 Binding。因为只有一个可以存在,ViewStubProxy 允许开发者在其上设置一个 OnInflateListener 它会在建立 Binding 后调用。 看代码:
XML文件:

<ViewStub
    android:layout_weight="1"
    android:id="@+id/view_stub"
    android:layout_width="0dp"
    android:layout_height="60dp"
    android:layout="@layout/view_stub"/>//引入ViewStub

MainActivity代码:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
    final User user = new User();
    user.firstName = "张三";
    user.lastName = "李四";
    binding.setUser(user);
    //一以下监听只是监听绑定时间而已,与显示与否无关
    binding.viewStub.setOnInflateListener(new ViewStub.OnInflateListener() {
        @Override
        public void onInflate(ViewStub stub, View inflated) {
            ViewStubBinding binding = DataBindingUtil.bind(inflated);
            binding.setUser(user);
        }
    });
}

/**
 * 显示ViewStub--在需要的地方调用
 * 无视红,运行之~
 */
public void inflateViewStub() {
    if (!binding.viewStub.isInflated()) {
        binding.viewStub.getViewStub().inflate();
    }
}

@Override
public void onBackPressed() {
    inflateViewStub();//简单的以Back键测试
    binding.tv.setText("ABCD");
    // super.onBackPressed();
}

5 动态 Variables

有时,不知道具体的Binding类,例如,一个RecyclerView 适配器对layouts任意操作并不知道具体的Binding类。它仍然必需在 onBindViewHolder期间赋值给 Binding

在这个例子中,该 RecyclerView 绑定的所有 layouts 有一个” item “的 Variable 。该 BindingHolder 有一个getBinding方法返回 ViewDataBinding
看下官方的示例:

public void onBindViewHolder(BindingHolder holder, int position) {
   final T item = mItems.get(position);
   holder.getBinding().setVariable(BR.item, item);
   holder.getBinding().executePendingBindings();
}

好吧,信息太少,再来一个:
RecyclerView 为例 AdapterDataBinding 需要动态生成,因此我们可以在 onCreateViewHolder 的时候创建这个 DataBinding,然后在 onBindViewHolder 中获取这个 DataBinding

public static class BindingHolder extends RecyclerView.ViewHolder {
    private ViewDataBinding binding;

    public BindingHolder(View itemView) {
        super(itemView);
    }

    public ViewDataBinding getBinding() {
        return binding;
    }

    public void setBinding(ViewDataBinding binding) {
        this.binding = binding;
    }
}

@Override
public BindingHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
    ViewDataBinding binding = DataBindingUtil.inflate(
            LayoutInflater.from(viewGroup.getContext()),
            R.layout.list_item,
            viewGroup,
            false);
    BindingHolder holder = new BindingHolder(binding.getRoot());
    holder.setBinding(binding);
    return holder;
}

@Override
public void onBindViewHolder(BindingHolder holder, int position) {
    User user = users.get(position);
    holder.getBinding().setVariable(BR.user, user);
    holder.getBinding().executePendingBindings();
}

注意此处 DataBindingUtil 的用法:

ViewDataBinding binding = DataBindingUtil.inflate(
    LayoutInflater.from(viewGroup.getContext()),
    R.layout.list_item,
    viewGroup,
    false);

还有另外一种比较简洁的方式,直接在构造 Holder 时把 View 与自动生成的 XXXBinding 进行绑定。

public class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserHolder> {
    private static final int USER_COUNT = 10;

    @NonNull
    private List<User> mUsers;

    public UserAdapter() {
        mUsers = new ArrayList<>(10);
        for (int i = 0; i < USER_COUNT; i ++) {
            User user = new User(RandomNames.nextFirstName(), RandomNames.nextLastName());
            mUsers.add(user);
        }
    }

    public static class UserHolder extends RecyclerView.ViewHolder {
        private UserItemBinding mBinding;

        public UserHolder(View itemView) {
            super(itemView);
            mBinding = UserItemBinding.bind(itemView);
        }

        public void bind(@NonNull User user) {
            mBinding.setUser(user);
        }
    }

    @Override
    public UserHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View itemView = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.user_item, viewGroup, false);
        return new UserHolder(itemView);
    }

    @Override
    public void onBindViewHolder(UserHolder holder, int position) {
        holder.bind(mUsers.get(position));
    }

    @Override
    public int getItemCount() {
        return mUsers.size();
    }
}

6 Immediate Binding

When a variable or observable changes, the binding will be scheduled to change before the next frame. There are times, however, when binding must be executed immediately. To force execution, use the executePendingBindings() method.

当变量的值更新的时候,Binding 对象将在下个更新周期中更新。这样就会有一点时间间隔,如果你像立刻更新,则可以使用 executePendingBindings 函数。


7 Background Thread

You can change your data model in a background thread as long as it is not a collection. Data binding will localize each variable / field while evaluating to avoid any concurrency issues.

只要不是集合变量,则可以在后台线程中更新数据。数据绑定将会保存每个变量的值到本地以避免多线程问题。

8 小结

这次主要学习了Binding类自定义名称,Include的使用、带ID的View的使用以及ViewStub、动态Variables的使用。
ViewStub的Demo地址:http://download.csdn.net/detail/cherish20151011/9464481

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值