Android开发提升效率之DataBinding——双向绑定

DataBingding

  1. Android开发提升效率之DataBinding——基本使用
  2. Android开发提升效率之DataBinding——进阶开发
  3. Android开发提升效率之DataBinding——双向绑定

双向绑定原理

  • 前言
  • 双向绑定
  • ViewDataBinding分析
  • 双向原理
  • 总结

博客创建时间:2021.04.12
博客更新时间:2021.04.13

以Android studio build=4.1.3,gradle=6.5,SdkVersion 30来分析讲解。如图文和网上其他资料不一致,可能是别的资料版本较低而已


前言

在早期的DataBinding双向绑定中需要防止死循环造成ANR,解决方案是需要判断前后两次值变动的id值是否一样。但是在现在的高版本中该bug已在底层中结局,我们在文章后面会详细说明。

双向绑定

为什么需要双向绑定?
假设一个登陆应用场景:
Android开发提升效率之DataBinding——双向绑定_第1张图片

  1. 打开应用,登录页面会自动填充上次登录保存User的name 和password。

    
        user.name="test"
        user.password="123456"
        binding.user=user
        
    	public class User {
    	 // 用户名
    	public String name;
    	 // 密码
    	 public String password;
    	}
    
  2. 如果此时想换一个用户登陆,常规方法是Edittext.getText获得name和password,然后进行登陆操作

  3. 现在使用双向绑定。

      <EditText
            android:id="@+id/etName"
            android:text="@={user.name}"
            android:inputType="text" />
    
        <EditText
            android:id="@+id/etPassword"
            android:text="@={user.password}"/>
    

    @={}就是双向绑定符

  4. 现在只要我们对name和password EditText输入内容进行改变分别为“admin”和“987654321”,那么user中对应的两个字段的值就会自动变动。

  5. 进行登陆操作时依然只用拿user来用就可以了。点击登陆按钮测试值

    else if(v?.id  ==R.id.btnLogin){
      Log.i("1111","name="+user.name+"  password="+user.password)
    }
    
    // 输出
    name=admin  password=987654321
    

ViewDataBinding分析

每个Fragment或Activity的布局开启DataBinding后都会生成一个ViewDataBinding子类。我们来分析其中关键源码

1. ActivityMainBinding 的初始化
ActivityMainBinding进行相关初始化设置,绑定数据与DataBinding的关联

    private ActivityMainBindingImpl(androidx.databinding.DataBindingComponent bindingComponent, View root, Object[] bindings) {
        //1. ActivityMainBinding 布局界面初始化,包括相关的值赋予
        invalidateAll();
    }

    /**
     * 初始化布局,并对控件的设值赋值
     */
    @Override
    public void invalidateAll() {
        synchronized(this) {
                mDirtyFlags = 0x10L;
        }
        // 请求重新绑定,主要是对控件的各值显示进行变动
        requestRebind();
    }

2. 指定变量赋值

    public void setLiveData(@Nullable com.xuanyuan.databindinganalysis.MyObservableField LiveData) {
        updateRegistration(0, LiveData);
        this.mLiveData = LiveData;
        synchronized(this) {
            mDirtyFlags |= 0x1L;
        }
        notifyPropertyChanged(BR.liveData);
        super.requestRebind();
    }

    public void setClick(@Nullable android.view.View.OnClickListener Click) {
        this.mClick = Click;
        synchronized(this) {
            mDirtyFlags |= 0x4L;
        }
        notifyPropertyChanged(BR.click);
        super.requestRebind();
    }

3. 通知更新指定变量

    // 控件的各值进行确定赋予
    @Override
    public boolean setVariable(int variableId, @Nullable Object variable)  {
        boolean variableSet = true;
        else if (BR.liveData == variableId) {
            setLiveData((com.xuanyuan.databindinganalysis.MyObservableField) variable);
        } else {
            variableSet = false;
        }
            return variableSet;
    }

4. 变量Change,通知UI刷新

    @Override
    protected void executeBindings() {
    ...
        if ((dirtyFlags & 0x11L) != 0) {
            androidx.databinding.adapters.TextViewBindingAdapter.setText(this.etName, liveDataGet);
        }
        if ((dirtyFlags & 0x10L) != 0) {
            // api target 1
       androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.etName, null,null, etNameandroidTextAttrChanged);
        }
    }

双向原理

当我们使用"@={}"双向绑定符时,观测ViewBindingIml代码。

1.常规双向绑定

    private androidx.databinding.InverseBindingListener etNameandroidTextAttrChanged = new androidx.databinding.InverseBindingListener() {
        @Override
        public void onChange() {
            java.lang.String callbackArg_0 = androidx.databinding.adapters.TextViewBindingAdapter.getTextString(etName);
            java.lang.String userName = null;
            boolean userJavaLangObjectNull = false;
            com.xuanyuan.databindinganalysis.User user = mUser;
            userJavaLangObjectNull = (user) != (null);
            if (userJavaLangObjectNull) {
                user.setName(((java.lang.String) (callbackArg_0)));
            }
        }
    };

	TextViewBindingAdapter.setTextWatcher(this.etName, null, null, null, etNameandroidTextAttrChanged);

其实这种双向绑定只是调用了 view.addTextChangedListener(newValue),对内容变动后的监听操作处理,源码中自动帮我们处理了。

2. Observable双向绑定

 val livaValue = MyObservableField()
 
 override fun onClick(v: View?) {
      if (v?.id == R.id.btnLogin) {
            val value = Math.random() * 1300
            livaValue.set(value.toString())
     }
 }
 
 <EditText
     android:id="@+id/etName"
     android:layout_width="match_parent"
     android:text="@={liveData}"
     android:inputType="text" />
  1. 当调用livaValue.set()时,阅读源码会发现有更新回调,最终执行ViewBinding的executeBindings()方法

    @Override
    protected void executeBindings() {
    ...
    }
    
  2. 更新调用后,EditText中的值变化,会触发TextChangedListener再次调用livaValue.set(value.toString()。此时EditText中的值变化中的值不再变化


总结

本文主要讲解了双向绑定的意义,如何使用双向绑定。

对于DataBinding的分析需要查看对应ViewDataBinding类,即可透过现象看本质。

本测试Demo源码
gitee:https://gitee.com/luofaxin/RxJava3Analysis.git
github:https://github.com/l424533553/RxJava3Analysis.git


相关链接

  1. Android开发提升效率之DataBinding——基本使用
  2. Android开发提升效率之DataBinding——进阶开发
  3. Android开发提升效率之DataBinding——双向绑定

扩展链接:

  1. LiveData原理深入浅出,透过源码看本质

扩展训练:

  1. 双向绑定的基本使用
  2. 双向绑定为何不会反复循环

博客书写不易,您的点赞收藏是我前进的动力,千万别忘记点赞、 收藏 ^ _ ^ !

你可能感兴趣的:(Android,Jetpack,DataBinding双向绑定,android,DataBinding,双向绑定原理)