androiddatabinding的简单介绍
本篇文章给大家谈谈androiddatabinding,以及对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。
本文目录一览:
Android-DataBinding原理分析
在MainActivity中,调用下面的方法:
app\build\intermediates\data_binding_layout_info_type_merge\debug\out
可以看到,这里定义了多个Target标签,这些Target的定义,其实就是定义对应的tag,将tag与activity_main.xml布局中的对应的View的id对应起来
经过DataBinding变化后的布局,会多出tag。
app/build/imtermediates/incremental/mergeDebugResources/stripped.dir/layout/activity_main.xml
其实DataBindingUtil的御烂setContentView()方法,主要就是调用activity的setContentView设置布局,并且绑定添加对应的View
这里的sMapper是一个DataBinderMapper对象,其实现类是DataBinderMapperImpl
DataBinderMapperImpl是通过apt注解处理器生成的。
这里的sMapper.getDataBinder()其实就是调用的MergedDataBinderMapper的getDataBinder()方法
而sMapper中的数据,其实就是DataBinderMapperImpl的构造器中调用其父类MergedDataBinderMapper 的addMapper()方法添加的对象
在DataBinding中有两个DataBinderMapperImpl类,一个是上面这个在androidx.databinding包下,继承了MergedDataBinderMapper的,另一个是在com.example.databindingdemo应用包下,直接继承DataBinderMapper。其实MergedDataBinderMapper也是继承自DataBinderMapper
这里要注意两点,就是如果是布局的顶层View,比如tag为layout/activity_main_0,那么就会new一个ActivityMainBindingImpl对象。这个tag,其实可以从前面看到的app/build/imtermediates/incremental/mergeDebugResources/stripped.dir/layout/activity_main.xml布局中的LinearLayout的tag知道
在new出ActivityMainBindingImpl对象后,则进行一些View的绑定操作,将通过tag取出的View与ActivityMainBindingImpl中对应的View属性进行绑定。
在这里,会调用了一个mapBindings方法,第三个参数是一个3,这个3的意思,就是activity_main.xml布局文件中有3个节点
mapBindings就会返回一个Object[] bindings数组。
这里的主要工作,就是将布局镇唤漏中的View保存在对应的bindings数组中,然后取出这个数组中的数据赋值给ActivityMainBindingImpl中的View
ActivityMainBindingImpl的父类ActivityMainBinding是在Eapp\build\generated\data_binding_base_class_source_out\debug\out\com\example\databindingdemo\databinding包下
BR的作用: 其实BR的作用,就用BR中的属性值来标记不同的操作需要的监听在mLocalFieldObservers数组中的位置
这里的localFieldId=0,这个id其实就BR文件中的id,就是BR文件中对应的静态final属性的值。而第二个就是观察者对象,链罩比如传入的ViewModel对象。
这里通过WeakListener监听器中的ObservableReference对象保存观察者与被观察者,当被观察者发生改变的时候,就会找到对应的WeakListener监听器,然后通知观察者做修改。
而ObservableReference方法的实现,有多个,比如:WeakPropertyListener。
这里让WeakListener.setTarget()其实就是通过WeakPropertyListener给被观察者添加callback,然后当被观察者数据发生改变的时候,被观察者通过遍历其内部的PropertyChangeRegistry中的OnPropertyChangedCallback回调(其实就是WeakPropertyListener),然后通过WeakPropertyListener监听通知给ViewDataBinding以及其实现类ActivityMainBindingImpl具体进行数据的处理和设置。
// 这里的mTarget其实是一个泛型T对象,而这个泛型是在WeakPropertyListener初始化WeakListener的时候传入的一个Observable,这个是databinding中的Observable,其子类实现就是BaseObservable
WeakPropertyListener中的addListener方法,就会给Observable添加一个callback回调,向Observable这个被观察者中添加callback的目的,就是在Observable数据发生变化的时候,遍历Observable中的mCallbacks这个callback集合,通知观察者进行修改。
从这第三步可以知道:
而WeakPropertyListener和WeakListener是相互持有的对方的引用。
在完成监听的相互绑定关系,并且给Observable添加了回调之后,就会回到ActivityMainBindingImpl的setUser()方法继续执行notifyPropertyChanged()方法。
但是这里的例子有个问题,就是监听是添加在User这个BaseObservable的子类中的,但是更新的时候,并不是通过这个User来进行通知,而是根据ActivityMainBindingImpl这个BaseObservable来通知,那么这个时候并不会通过ActivityMainBindingImpl的调用notifyPropertyChanged()最终拿到User中的PropertyChangeRegistry对象mCallbacks,所以起作用的并不是这句话。而最终ActivityMainBindingImpl在设置User起刷新作用,是因为super.requestRebind()的调用也触发了mRebindRunnable任务的执行,其实就是没有通过PropertyChange来触发requestRebind()
这里其实就是调用的BaseObservable的notifyPropertyChanged()方法,因为ActivityMainBindingImpl是ViewDataBinding的子类,而ViewDataBinding继承了BaseObservable类
这里的mNotifier.notifyCallback其实就会调用到下面的PropertyChangeRegistry中定义的NOTIFIER_CALLBACK 属性中的onNotifyCallback实现,而这里的callback其实就是WeakPropertyListener,因为WeakPropertyListener是OnPropertyChangedCallback的子类,这里其实会回调给mLocalFieldObservers数组中所有的WeakListener
从mListener中取出target,而这里的mListener其实就是,WeakListener,而每个被观察者,其实都是有一个对应的LocalFieldId,这个id就是BR文件中定义的,刚才的流程中,我们传入的是0,所以这里的 mLocalFieldId=0
这里的onFieldChange的方法的实现,就是在ActivityMainBindingImpl.java中
这里因为fieldId=0,所以会进入第一个if条件if (fieldId == BR._all),所以会返回true,所以就会返回到ViewDataBinding.java中的handleFieldChange方法中,继续执行requestRebind()
这里最终都会执行mRebindRunnable的run()方法。只不过SDK版本大于等于16的时候,会采用Choreographer编舞者来处理,而之前的版本则是采用Handler来执行。
在这里最终就会执行到executeBindings()方法,而该方法的实现,又是在ActivityMainBindingImpl.java中
如果自定义类继承了BaseObservable类,则会更新注册监听。即BaseObservable保存PropertyChangeRegistry对象,该对象中会保存WeakPropertyListener监听,而WeakPropertyListener监听会持有WeakListener,WeakListener也会持有WeakPropertyListener,并且持有一个BaseObservable的target,这个target就是自定义的BaseObservable子类实现对象,在设置target的时候就会将WeakPropertyListener监听给保存在这个target中的PropertyChangeRegistry对象中,当使用自定义的BaseObservable进行更新的时候,就可以通过监听回调的方式通知到ActivityMainBindingImpl这些ViewDataBinding中,然后向ActivityMainBindingImpl解析得到的View实体中设置对应的数据。
通过WeakListener监听器中的ObservableReference对象保存观察者与被观察者,当被观察者发生改变的时候,就会找到对应的WeakListener监听器,然后通知观察者做修改。
而ObservableReference方法的实现,有多个,比如:WeakPropertyListener。
这里让WeakListener.setTarget()其实就是通过WeakPropertyListener给被观察者添加callback,然后当被观察者数据发生改变的时候,被观察者通过遍历其内部的PropertyChangeRegistry中的OnPropertyChangedCallback回调(其实就是WeakPropertyListener),然后通过WeakPropertyListener监听通知给ViewDataBinding以及其实现类ActivityMainBindingImpl具体进行数据的处理和设置。
其实就是向ViewModel或者自定义的Observable(是databinding中的Observable)的子类实现中的mCallbacks中添加监听WeakPropertyListener,用于数据变化回调。而在WeakPropertyListener中的WeakListener对象会保存这个Observable为target,用于在更新的时候取出。
比如在xml布局的data中直接使用Boolean、Integer、String等类型
如果ActivityMainBindingImpl中设置的是比如ViewModel,那么就需要看是否使用了LiveData修饰的属性,如果没有使用LiveData的,则并不会去更新注册监听信息,而只是重新保存ViewDataBinding中保存的数据实体,并且直接调用ActivityMainBinding中保存的View实体进行设置新的数据
如果是使用了LiveData的话,则会在调用LiveDataListener(这是一个Observer子类与上面的WeakPropertyListener类似)的addListener的时候,就会给LiveData注册观察者LiveDataListener,然后在LiveDataListener中的onChanged实现中通过调用ViewDataBinding的handleFieldChange方法触发数据变化修改,进而更新View显示的数据
[img]Android,DataBinding的官方双向绑定
在Android Studio 2.1 Preview 3之后,官方开始支持双向绑定了。
可惜目前Google并没有在Data Binding指南里面加入这个教程,并且在整个互联网之中塌旅野只有 这篇文章 介绍了如何使用反向绑定。
在阅读一下文章之前,我假设你已经知道如何正向绑定。
在正向绑定中,我们在Layout里面的绑定表达式是这样的:
当user.name的数据改动时,我们的TextView都会同步改变文字。
现在假设一种情况,当你更换成EditText时,如果你的用户名User.name已经绑定到 EditText 中,当用户输入文字的时候,你原来的user.name数据并没有同步改动,因此我们需要修改成:
看出微小的差别了吗?对,就是"@{}"改成了"@={}",是不是很简单?
同样你团喊也可以在别的View上引用属性:
当CheckBox的状态发生改变的时候,ImageView也会同时发生改变。在复杂情况下,这个特性没什么卵用,因为逻辑部分我们是不建议写在XML中。
开启双向绑定,需要在项目的build.gradle中设置:
同样,你需要在你Module的build.gradle中设置:
我们刚才的例子里面只显示了系统自带的应用,那么如果是自定义控件,或者是我们更细颗粒度的 Observable 呢?等下就揭晓如何自定义自己的双向绑定,我们来看看目前Android支持的控件:
设想一下我们使用了下拉刷新 SwipeRefreshLayout 控件,这个时候我们希望在加载数据的时候能控制refreshing的状态,所以我们加入了 ObservableBoolean 的变量swipeRefreshViewRefreshing来正向绑定数据,并且能够在用户手动下拉刷新的时候同步更新swipeRefreshViewRefreshing数据:
接下来我们需要告诉框架,我们需要将 SwipeRefreshLayout 的isRefreshing的值反向绑定到 swipeRefreshViewRefreshing :
这是一种简单的定义,其中event和method都不是必须的,因为系统会自动生成,写出来是为了更好地了解如何绑定的,可以参镇纳考官方文档 InverseBindingMethod 。
当然你也可以使用另外一种写法,并且如果你的值并不是直接对应 Observable 的值的时候,就可以在这里进行转换:
上面的event同样也不是必须的。以上的定义都是为了让我们能够在布局文件中使用"@={}"这个双向绑定的特性。接下来你需要告诉框架如何处理refreshingAttrChanged事件,就像处理一般的监听事件一样:
一般情况下,我们都需要设置正常的OnRefreshListener,所以我们可以合并写成:
现在我们终于可以使用双向绑定的技术啦。但是要注意,需要设置 requireAll = false ,否则系统将识别不了refreshingAttrChanged属性,前文提到的文章例子里并没有设置这个。
在ViewModel中,我们的数据是这样的:
在布局文件中是这样设置的:
最后我们还有一个小问题,就是双向绑定有可能会出现死循环,因为当你通过Listener反向设置数据时,数据也会再次发送事件给View。所以我们需要在设置一下避免死循环:
这样就没问题啦。
Android databinding不存在
1.gradle里面开关是否开启
android {
....
dataBinding {
enabled = true
}
}
2.也应该就是这个问题: 那就是你代码写错了,导致你的xxxxxbing.java文件没有生成,去碰和你的build文件夹下查看一下,具体目录结构如下,包名肯定是你自己的包名。一般错误原因有: 1、方法名不对应 2.xml语法有问题 3、类名的塌吵知全路径写错了 ,建议检查上述错误语法有没有问题,确认无误后删除build文件夹,clean 和rebuild一下project 或者重启studio,然后看是否还有错误提示,不过最重要的是一定要认真团消看报错信息,你图片左面小工具栏倒数第二个,一个记事本的小图标,就是message模块,点进去可以看更详细的报错信息。
关于androiddatabinding和的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。