关于DataBinding的一些记录和感想

    近段时间一些事情原因没有坚持写博客了,内心很纠结,本来很想就databinding来写一些自己的感想,但是一直拖到现在,心累,好了,不多说,别忘记重要事情

    其实databinding的出现简洁了xml文件,顾名思义,就是数据绑定。那么如何来实现数据绑定呢?它又是怎么样去工作的呢?

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <import type="android.view.View" />

        <variable
            name="customer"
            type="com.example.wh.databindingdemo.Customer" />

        <variable
            name="presenter"
            type="com.example.wh.databindingdemo.MainActivity.Presenter" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="com.example.wh.databindingdemo.MainActivity">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="@{()-> presenter.changeName()}"
            android:text="@{customer.name}"
            />

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onTextChanged="@{presenter.onTextChanged}" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{customer.id}"
            android:onTextChanged="@{presenter.onTextChanged}"
            />

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onTextChanged="@{presenter.onTextChanged}"
            />
<Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:onClick="@{()-> presenter.StarActivity()}"
    />
    </LinearLayout>
</layout>

这个事一个简单的布局,跟常规布局就是多了外层跟布局layout,那么这个layout是干什么的呢?其实类似H5标签的头标签,描述当前布局信息的,variable其实就是一个属性描述,简单来讲,就是当前数据绑定到类中的属性。

    下面我们看看怎么绑定数据的,首先看看Java代码中怎么去设置,

 ActivityMainBinding mBinding;
 Customer customer = new Customer("wh","9527");

 @Override
 protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     mBinding = DataBindingUtil.setContentView(this,R.layout.activity_main);
     mBinding.setPresenter(new Presenter());
     mBinding.setCustomer(customer);

 }
public class Presenter{
     public void changeName(){
         Toast.makeText(MainActivity.this,"点击了"+customer.getName(),Toast.LENGTH_SHORT).show();
     }
     public void onTextChanged(CharSequence s, int start, int before, int count)  {
         customer.setName(s.toString());
         mBinding.setCustomer(customer);
         if (s.toString().equals("")){
             customer.setId("6666");
             mBinding.setCustomer(customer);
         }
     }
     public void StarActivity(){
         Intent intent = new Intent(MainActivity.this,ListActivity.class);
         startActivity(intent);
     }

 }

当我们设置了databinding后,系统默认为我们生成了当前activity对应的databinding,就是代码里的ActivityMainDataBinding,在xml中我们分别在TextView和edittext中设置显示了customer的ID和name,那么数据是怎么绑定的呢?下面我们来看看源码。

@NonNull
private final android.widget.TextView mboundView1;
@NonNull
private final android.widget.EditText mboundView2;
@NonNull
private final android.widget.TextView mboundView3;
@NonNull
private final android.widget.EditText mboundView4;
@NonNull
private final android.widget.Button mboundView5;

这是databinding默认生成对应布局文件的几个控件,那么怎么设置到对应控件上面的呢?继续看源码

@Override
protected void executeBindings() {
    long dirtyFlags = 0;
    synchronized(this) {
        dirtyFlags = mDirtyFlags;
        mDirtyFlags = 0;
    }
    com.example.wh.databindingdemo.MainActivity.Presenter presenter = mPresenter;
    java.lang.String customerId = null;
    android.databinding.adapters.TextViewBindingAdapter.OnTextChanged presenterOnTextChangedAndroidDatabindingAdaptersTextViewBindingAdapterOnTextChanged = null;
    java.lang.String customerName = null;
    com.example.wh.databindingdemo.Customer customer = mCustomer;

    if ((dirtyFlags & 0x5L) != 0) {



            if (presenter != null) {
                // read presenter::onTextChanged
                presenterOnTextChangedAndroidDatabindingAdaptersTextViewBindingAdapterOnTextChanged = (((mPresenterOnTextChangedAndroidDatabindingAdaptersTextViewBindingAdapterOnTextChanged == null) ? (mPresenterOnTextChangedAndroidDatabindingAdaptersTextViewBindingAdapterOnTextChanged = new OnTextChangedImpl()) : mPresenterOnTextChangedAndroidDatabindingAdaptersTextViewBindingAdapterOnTextChanged).setValue(presenter));
            }
    }
    if ((dirtyFlags & 0x6L) != 0) {



            if (customer != null) {
                // read customer.id
                customerId = customer.getId();
                // read customer.name
                customerName = customer.getName();
            }
    }
    // batch finished
    if ((dirtyFlags & 0x4L) != 0) {
        // api target 1

        this.mboundView1.setOnClickListener(mCallback1);
        this.mboundView5.setOnClickListener(mCallback2);
    }
    if ((dirtyFlags & 0x6L) != 0) {
        // api target 1

        android.databinding.adapters.TextViewBindingAdapter.setText(this.mboundView1, customerName);
        android.databinding.adapters.TextViewBindingAdapter.setText(this.mboundView3, customerId);
    }
    if ((dirtyFlags & 0x5L) != 0) {
        // api target 1

        android.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.mboundView2, (android.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (android.databinding.adapters.TextViewBindingAdapter.OnTextChanged)presenterOnTextChangedAndroidDatabindingAdaptersTextViewBindingAdapterOnTextChanged, (android.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, (android.databinding.InverseBindingListener)null);
        android.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.mboundView3, (android.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (android.databinding.adapters.TextViewBindingAdapter.OnTextChanged)presenterOnTextChangedAndroidDatabindingAdaptersTextViewBindingAdapterOnTextChanged, (android.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, (android.databinding.InverseBindingListener)null);
        android.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.mboundView4, (android.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (android.databinding.adapters.TextViewBindingAdapter.OnTextChanged)presenterOnTextChangedAndroidDatabindingAdaptersTextViewBindingAdapterOnTextChanged, (android.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, (android.databinding.InverseBindingListener)null);
    }
}
dirtyFlag这个事一个标志,对应的是当前控件的一个标志,我们可以看到在这段代码中可以找到settext,分别传入的控件和数据,

这段代码其实就是绑定数据和监听事件来操作数据显示的。

回头捋一下思路,首先,我们在XML文件中设置variable,这个指代的是我么需要的数据来源和类型,然后在控件上去绑定数据源,底层databinding会根据我们给的数据源去settext,将数据显示出来,

那如果我在输入框上改变文字,然后将文字再重新显示呢?其实databinding早就做了这个,这个就是数据的双向绑定,在presenter中我们看到设置监听事件,这个时候回,当我们改变输入框的文本,获取到文本,将文本赋给类中的属性,然后TextView在重新获取类中新的属性值。这就是数据的双向绑定,view-->model---->view


@Override
public boolean setVariable(int variableId, @Nullable Object variable)  {
    boolean variableSet = true;
    if (BR.presenter == variableId) {
        setPresenter((com.example.wh.databindingdemo.MainActivity.Presenter) variable);
    }
    else if (BR.customer == variableId) {
        setCustomer((com.example.wh.databindingdemo.Customer) variable);
    }
    else {
        variableSet = false;
    }
        return variableSet;
}

在这段代码中databinding做的操作是,判断variableId对应的是哪一个?那么这个variableId怎么来的呢?其实回到xml文件中可以看到,每一个variable都对应一个name,这个name其实就是对应源码中的ID,这个过程就是根据XML文件来设置variable的,那么这个又有什么用的呢?现在我们想在列表中去使用databinding,那么怎么去使用呢?

这就必须涉及了adapter,

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

<data>
    <variable
        name="item"
        type="com.example.wh.databindingdemo.User"/>
</data>
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    >
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{item.company}"
    />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{item.position}"
        android:layout_marginLeft="20dp"
        />
</LinearLayout>
</layout>

/**
 * 作者 ;Created by ${wh} on 2018/3/25.
 */

public class UserAdapter extends RecyclerView.Adapter<BindingViewHolder> {
    private List<User> users;
    private Context mContext;
    private LayoutInflater layoutInflater;
    private OnItemClickLisener lisener;
    public interface OnItemClickLisener{
        void onItemClick(int p);
    };

    public UserAdapter(Context mContext) {
        this.mContext = mContext;
        users = new ArrayList<>();
        layoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public BindingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        ViewDataBinding binding;
        binding = DataBindingUtil.inflate(layoutInflater,R.layout.list_item,parent,false);
        return new BindingViewHolder(binding);
    }

    @Override
    public void onBindViewHolder(BindingViewHolder holder, final int position) {
        User user = users.get(position);
        holder.getmBinding().setVariable(BR.item,user);
        holder.getmBinding().executePendingBindings();
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (lisener!=null){
                    lisener.onItemClick(position);
                }
            }
        });
    }

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

    public void setLisener(OnItemClickLisener lisener) {
        this.lisener = lisener;
    }
    public void addUser( User u){
        int p = new Random().nextInt(4);
        users.add(p,u);
        notifyItemInserted(users.size());
    }
    public void addAll( List<User> u){
        users.addAll(u);
        notifyItemInserted(users.size());
    }
    public void remove(int p){
        if (users.size()>0){
            users.remove(p);
        }
        notifyItemRemoved(p);
    }
}

在onBindViewHolder中填充数据的时候,我们user实体对象添加到variable中去,在源码中我们可以看到,databinding会根据xml文件去自己将数据显示出来,这样节省了之前我们不断去根据xml中控件ID来设置settext。

 以上是自己结合源码对databinding的工作流程做一个大概的描述,这个demo也只是说明一下源码,后续会在项目给大家展示databinding更多的用法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值