上篇写了dataBinding的使用和封装,今天我们就分析下源码。
首先我们从 DataBindingUtil.setContentView(this,R.layout.activity_main);方法作为入口,发现最后还是调用activity的setContentView()方法。
//最后会调用bind()方法,这个方法会调用 DataBindingMapper类的getDataBinder()方法
点击DataBindingMapper类发现getDataBinder方法是个抽象方法,他的子类DataBindingMapperImpl类实现了这个方法,我们看看这个方法根据view的tag创建一个ActivityMainBindingImpl类(命名是根据xml布局名+BindingImpl)
这时有人会问,哪个tag怎么来的,其实,当我们再布局里面使用layout作为根布局再写了data标签,build后,系统会自动生成两个xml文件
//我们点开activity_main 发现里面的布局就是去掉layout和data的正常布局,并且在每个控件添加了一个tag标记
//再打开activity_mian_layout文件,发现就是记录所有节点标签的信息,比如名称代码的开始行结束行等等信息。(如果你开代码是一行的,可以格式化代码 Windows快捷键 ctrl + shift+ F)
回到我们上面讲的DataBinderMapperImpl的getDataBinder()方法,根据布局tag创建对应的**BindingImpl类;其实ActivityMainBindingImpl类是ActivityMainDataBining的子类 ;ActivityMainDataBining是ViewDataBinding的子类;其实DataBinding.setContentView()方法设置布局,根据布局tag返回对应的ViewDataBinding对象;DataBinding.setContextView()源码就分析到这了。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面我们分析设置数据 activityMainBinding.setUser();
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
User user = new User("张三");
activityMainBinding.setUser(user);
}
}
//点击源码看到是个抽象类,那一定是其子类实现啦。其实核心逻辑在其子类ActivityMainBinderImpl类里面
//那我们看看ActivityMainBinderImpl的setUser()方法;代码很简单,给类里面的mUser赋值,再调用个notifyPropertyChanged()方法。
//点击notifyPropertyChanded方法;当你点击进去发现跟踪到最后是个onNotifyCallback()的抽象方法,貌似跟踪到了一个死胡同。这时我们可以看看他的父类 ViewDataBinding的代码。发现有个静态代码块
执行线程,看看线程代码最终执行了一个excutePendingBindings()方法
跟踪executePendingBindings()方法最后跟踪到一个executeBinding()抽象方法,那看看他子类ActivityMainBindingImpl实现这个方法代码,看到估计大家就比较清晰了,给我们创建的User赋值,获取name变量,调用TextViewBindingAdapter的setText方法,
点击setText方法,代码如下,这时一切就真相大白了。其实就是调用系统的TextView.setText()方法。
//到这里可能有人会问那TextView从哪里来的呢?其实很简单,代码如下
在构造方法获取的在解析Xml文件时,从根节点一个一个解析保存到bindings数组里面。根据tag信息字段对应节点是什么控件。
---------------------------------------------------------------------------数据驱动UI,实现双向绑定------------------------------------------------------
如果想数据变化UI跟随变,需要viewModel继承BaseObserable,在get方法使用@Bindable注解
在set方法调用notifyPorpertyChanged()方法 ,代码如下
public class User extends BaseObservable { private String name; public User(String name) { this.name = name; } @Bindable public String getName() { return name; } public void setName(String name) { this.name = name; notifyPropertyChanged(BR.name); } }
我在activity测试代码。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
final User user = new User("张三");
activityMainBinding.setUser(user);
//测试数据双向绑定,数据驱动UI变化
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
user.setName("李四");
}
}, 5000);
}
}
//我点击ViewDataBinding构造方法源码,打断点,发现通过回调接口FrameCallback的doFrame方法执行线程的run方法,
//线程代码如下,最终会执行executePendingBindings()方法;
//这个方法最后会执行一个抽象方法executeBindings();
ActivityMainBingingImpl是ViewDataBing的子类,实现了executeBindings()方法,流程就跟上面分析一样了。
说白了就是通过回调接口实现数据双向绑定,最终还是调用系统的API设置数据更新Ui
//好了DataBinding源码分析就到这里。
最后附上一张我画的时序图