Data binding 在2015年7⽉发布的Android Studio v1.3.0 版本上引⼊,在2016年4月Android Studio v2.0.0 上正式⽀持。⽬前为⽌,DataBinding 已经⽀持双向绑定了。Databinding 是⼀个实现数据和UI绑定的框架,是⼀个实现 MVVM 模式的⼯具,有了 Data Binding,在Android中也可以很⽅便的实现MVVM开发模式。Data Binding 是⼀个support库,最低⽀持到Android 2.1(API Level 7+)。Data Binding 的作用就是可以通过声明式布局来绑定xml,使用了DataBinding,我们就不用在java类中写findViewById、setText,setVisibility,setEnabled、setOnClickListener等这些大量重复的代码,因为DataBinding的原理实际上就是通过APT技术,在编译的时候自动帮我们把这些代码写了,我们只需要对它进行绑定就可以了,使用DataBinding能够轻松实现MVVM模式。
二、DataBinding的使用(Kotlin版)注意:在使用DataBinding的时候,一定要在build.gradle中把DataBinding的开关打开:
dataBinding{
enabled true
}
1、activity_main.xml
2、User.kt
class User {
val name:ObservableField by lazy { ObservableField() }
val pwd:ObservableField by lazy { ObservableField() }
}
3、MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//绑定布局
val bing = DataBindingUtil.setContentView
(this,R.layout.activity_main4)
//设置数据来源
val user = User()
user.name.set("张三")
user.pwd.set("123456")
bing.user = user
}
}
三、DataBinding的源码分析
1、xml布局分析
首先,我们分析布局变化,前面已经说过,DataBinding是通过APT技术来实现的,也就是说,在我们绑定了布局并且编译之后,编译工具会自动生成一些布局相关的代码,因此,我们可以打开编译后生成的布局文件来进行分析,具体路径:build\intermediates\data_binding_layout_info_type_merge\debug\out\activity_main.xml
false
false
可以看到,编译工具生成的布局文件定义了了多个Target标签,这些Target的定义,其实就是定义对应的tag,将tag与activity_main.xml布局中的对应的View的id对应起来经过DataBinding变化后的布局,就会有多个tag,同时打开build\intermediates\incremental\mergeDebugResources\stripped.dir\layout\activity_main.xml,我们竟然可以看到没有任何绑定的的xml布局:
也就是说,DataBinding帮我们把我们在开发过程中编写的xml布局分成了两个部分,一部分是通过定义Target来把View和id关联起来,另一部分就是去掉了DataBinding的布局本身。
2、DataBindingUtil.setContentView原理 DataBindingUtil.setContentView(this,R.layout.activity_main4)
(1)DataBindingUtil.setContentView()
点进去看源码,我们会发现,其实DataBindingUtil的setContentView方法,主要就是调用了activity的setContentView设置布局,并且绑定添加对应的View:
public static T setContentView(@NonNull Activity activity,
int layoutId, @Nullable DataBindingComponent bindingComponent) {
activity.setContentView(layoutId);
View decorView = activity.getWindow().getDecorView();
ViewGroup contentView = (ViewGroup) decorView.findViewById(android.R.id.content);
return bindToAddedViews(bindingComponent, contentView, 0, layoutId);
}
private static T bindToAddedViews(DataBindingComponent component,
ViewGroup parent, int startChildren, int layoutId) {
final int endChildren = parent.getChildCount();
final int childrenAdded = endChildren - startChildren;
if (childrenAdded == 1) {
final View childView = parent.getChildAt(endChildren - 1);
return bind(component, childView, layoutId);
} else {
final View[] children = new View[childrenAdded];
for (int i = 0; i < childrenAdded; i++) {
children[i] = parent.getChildAt(i + startChildren);
}
return bind(component, children, layoutId);
}
}
(2)DataBindingUtil.bind()方法
static T bind(DataBindingComponent bindingComponent, View[] roots,
int layoutId) {
return (T) sMapper.getDataBinder(bindingComponent, roots, layoutId);
}
这里的sMapper是一个DataBinderMapper对象,其实现类是DataBinderMapperImpl,DataBinderMapperImpl是通过apt注解处理器生成的(生成的文件目录位置:build\generated\ap_generated_sources\debug\out\包名),这里的sMapper.getDataBinder()其实就是调用了MergedDataBinderMapper的getDataBinder()方法,而sMapper中的数据,其实就是DataBinderMapperImpl的构造器中调用其父类MergedDataBinderMapper的addMapper()方法添加的对象。
public ViewDataBinding getDataBinder(DataBindingComponent component, View view, int layoutId) {
int localizedLayoutId = INTERNAL_LAYOUT_ID_LOOKUP.get(layoutId);
if(localizedLayoutId > 0) {
final Object tag = view.getTag();
if(tag == null) {
throw new RuntimeException("view must have a tag");
}
switch(localizedLayoutId) {
case LAYOUT_ACTIVITYMAIN4: {
if ("layout/activity_main4_0".equals(tag)) {
return new ActivityMain4BindingImpl(component, view);
}
throw new IllegalArgumentException("The tag for activity_main4 is invalid. Received: " + tag);
}
}
}
return null;
}
在getDataBinder方法里,需要注意两点,就是如果布局的顶层View,比如tag为layout/activity_main_0,那么就会new出一个ActivityMainBindingImpl对象。这个tag其实可以从前面看到的build\intermediates\incremental\mergeDebugResources\stripped.dir\layout\activity_main.xml布局中的LinearLayout的tag得知。
(3)ActivityMainBindingImpl构造器
通过apt注解器生成的ActivityMainBindingImpl这个对象,会对View进行一些绑定 *** 作,把通过tag取出的View与ActivityMainBindingImpl中对应的View属性进行绑定。
public ActivityMain4BindingImpl(@Nullable androidx.databinding.DataBindingComponent bindingComponent, @NonNull View root) {
this(bindingComponent, root, mapBindings(bindingComponent, root, 3, sIncludes, sViewsWithIds));
}
protected static Object[] mapBindings(DataBindingComponent bindingComponent, View root,
int numBindings, IncludedLayouts includes, SparseIntArray viewsWithIds) {
Object[] bindings = new Object[numBindings];
mapBindings(bindingComponent, root, bindings, includes, viewsWithIds, true);
return bindings;
}
在这里会调用一个mapBindings方法,第三个参数的意思是布局文件下的节点数(例如我的activity_main.xml里有3个节点,而生成的是3)。这里值得注意的是,mapBindings返回的是一个Object[] bindings数组,其实就是将布局中的View保存在对应的bindings数组中,然后取出这个数组中的数据赋值给ActivityMainBindingImpl中的View,这个 *** 作是很消耗性能的。
而ActivityMainBindingImpl的父类,其实就位置于build\generated\data_binding_base_class_source_out\debug\out\包名下:
public abstract class ActivityMain4Binding extends ViewDataBinding {
@Bindable
protected User mUser;
protected ActivityMain4Binding(Object _bindingComponent, View _root, int _localFieldCount) {
super(_bindingComponent, _root, _localFieldCount);
}
public abstract void setUser(@Nullable User user);
@Nullable
public User getUser() {
return mUser;
}
...
}
4、ActivityMainBinding.setUser解析
(1)BR文件
public class BR {
public static final int _all = 0;
public static final int user = 1;
}
BR文件位于build\generated\ap_generated_sources\debug\out\包名下,其作用是定义不同的属性值来标记不同的 *** 作需要的监听在mLocalFieldObservers数组中的位置。
(2)ActivityMain4BindingImpl.setUser()
public void setUser(@Nullable com.yexing.databinding.User User) {
this.mUser = User;
synchronized(this) {
mDirtyFlags |= 0x4L;
}
//通知user保存数据
notifyPropertyChanged(BR.user);
super.requestRebind();
}
(3)ViewDataBind.updateRegistration()
private boolean updateRegistration(int localFieldId, Object observable,
CreateWeakListener listenerCreator) {
if (observable == null) {
return unregisterFrom(localFieldId);
}
WeakListener listener = mLocalFieldObservers[localFieldId];
if (listener == null) {
registerTo(localFieldId, observable, listenerCreator);
return true;
}
//根据BR的每个属性的属性值做index,存储每个BR属性对应的监听器
if (listener.getTarget() == observable) {
return false;//nothing to do, same object
}
unregisterFrom(localFieldId);
registerTo(localFieldId, observable, listenerCreator);
return true;
}
//这个方法其实就是将Activity这个观察者和User这个被观察者统一添加到ObservableFeference中
protected void registerTo(int localFieldId, Object observable,
CreateWeakListener listenerCreator) {
if (observable == null) {
return;
}
WeakListener listener = mLocalFieldObservers[localFieldId];
if (listener == null) {
//通过属性监听器的创建器创建一个BR属性值对应的监听器
listener = listenerCreator.create(this, localFieldId);
mLocalFieldObservers[localFieldId] = listener;
//将监听器与观察者做绑定,这里的观察者其实就是activity
if (mLifecycleOwner != null) {
listener.setLifecycleOwner(mLifecycleOwner);
}
}
//将监听器与被观察者做绑定,被观察者是User
listener.setTarget(observable);
}
这里通过WeakListener监听器中的ObservableReference对象保存观察者与被观察者,当被观察者发生改变的时候,就会找到对应的WeakListener监听器,然后通知观察者做修改。这里的listner.setTarget()其实就是通过WeakPropertyListener给被观察者添加callback,然后当被观察者数据发生改变的时候,被观察者通过遍历其内部的PropertyChangeRegistry中的OnPropertyChangedCallback回调,然后通过WeakPropertyListener监听通知给ViewDataBinding以及其实现类ActivityMainBindImpl具体进行数据的处理和设置。
(4)WeakListener.setTarget()
public void setTarget(T object) {
unregister();
mTarget = object;
if (mTarget != null) {
mObservable.addListener(mTarget);
}
}
这里的mTarget是一个泛型对象,这个泛型是在WeakPropertyListener初始化WeakListener的时候传入的一个Observable,这个是databinding中的Observable,其子类实现就是BaseObservable。WeakPropertyListener中的addListener方法会给Observable添加一个callback回调,向Observable这个被观察者中添加callback的目的,就是在Observable数据发生变化的时候,遍历Observable中的mCallbacks这个集合,通知观察者进行修改,这个 *** 作也是相当消耗性能的。
private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
implements ObservableReference {
final WeakListener mListener;
public WeakPropertyListener(ViewDataBinding binder, int localFieldId) {
mListener = new WeakListener(binder, localFieldId, this);
}
@Override
public WeakListener getListener() {
return mListener;
}
@Override
public void addListener(Observable target) {
target.addOnPropertyChangedCallback(this);
}
@Override
public void removeListener(Observable target) {
target.removeOnPropertyChangedCallback(this);
}
@Override
public void setLifecycleOwner(LifecycleOwner lifecycleOwner) {
}
@Override
public void onPropertyChanged(Observable sender, int propertyId) {
ViewDataBinding binder = mListener.getBinder();
if (binder == null) {
return;
}
Observable obj = mListener.getTarget();
if (obj != sender) {
return; // notification from the wrong object?
}
binder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId);
}
}
BaseObservable这个被观察者会被WeakListener持有,而WeakListener会被WeakPropertyListener持有,从而BaseObservable会间接的被WeakPropertyListener持有。而BaseObservable会通过mCallbacks持有Observable.OnPropertyChangedCallback对象,而Observable.OnPropertyChangedCallback的子类是WeakPropertyListener,所以BaseObservable也会持有WeakPropertyListener对象。而WeakPropertyListener和WeakListener是相互持有的,在完成监听并且给Observable添加了回调之后,就会回到ActivityMainBindImpl的setUser()方法继续执行notifyPropertyChanged()方法。
(5)Observable.notifyPropertyChanged()方法
/**
* Notifies listeners that a specific property has changed. The getter for the property
* that changes should be marked with {@link Bindable} to generate a field in
* BR
to be used as fieldId
.
*
* @param fieldId The generated BR id for the Bindable field.
*/
public void notifyPropertyChanged(int fieldId) {
synchronized (this) {
if (mCallbacks == null) {
return;
}
}
mCallbacks.notifyCallbacks(this, fieldId, null);
}
/**
* Notify all callbacks.
*
* @param sender The originator. This is an opaque parameter passed to
* {@link CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int, Object)}
* @param arg An opaque parameter passed to
* {@link CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int, Object)}
* @param arg2 An opaque parameter passed to
* {@link CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int, Object)}
*/
public synchronized void notifyCallbacks(T sender, int arg, A arg2) {
mNotificationLevel++;
notifyRecurse(sender, arg, arg2);
mNotificationLevel--;
if (mNotificationLevel == 0) {
if (mRemainderRemoved != null) {
for (int i = mRemainderRemoved.length - 1; i >= 0; i--) {
final long removedBits = mRemainderRemoved[i];
if (removedBits != 0) {
removeRemovedCallbacks((i + 1) * Long.SIZE, removedBits);
mRemainderRemoved[i] = 0;
}
}
}
if (mFirst64Removed != 0) {
removeRemovedCallbacks(0, mFirst64Removed);
mFirst64Removed = 0;
}
}
}
/**
* Notify up to the first Long.SIZE callbacks that don't have a bit set in removed
.
*
* @param sender The originator. This is an opaque parameter passed to
* {@link CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int, Object)}
* @param arg An opaque parameter passed to
* {@link CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int, Object)}
* @param arg2 An opaque parameter passed to
* {@link CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int, Object)}
*/
private void notifyFirst64(T sender, int arg, A arg2) {
final int maxNotified = Math.min(Long.SIZE, mCallbacks.size());
notifyCallbacks(sender, arg, arg2, 0, maxNotified, mFirst64Removed);
}
/**
* Notify all callbacks using a recursive algorithm to avoid allocating on the heap.
* This part captures the callbacks beyond Long.SIZE that have no bits allocated for
* removal before it recurses into {@link #notifyRemainder(Object, int, A, int)}.
*
* Recursion is used to avoid allocating temporary state on the heap.
*
* @param sender The originator. This is an opaque parameter passed to
* {@link CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int, Object)}
* @param arg An opaque parameter passed to
* {@link CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int, Object)}
* @param arg2 An opaque parameter passed to
* {@link CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int, Object)}
*/
private void notifyRecurse(T sender, int arg, A arg2) {
final int callbackCount = mCallbacks.size();
final int remainderIndex = mRemainderRemoved == null ? -1 : mRemainderRemoved.length - 1;
// Now we've got all callbakcs that have no mRemainderRemoved value, so notify the
// others.
notifyRemainder(sender, arg, arg2, remainderIndex);
// notifyRemainder notifies all at maxIndex, so we'd normally start at maxIndex + 1
// However, we must also keep track of those in mFirst64Removed, so we add 2 instead:
final int startCallbackIndex = (remainderIndex + 2) * Long.SIZE;
// The remaining have no bit set
notifyCallbacks(sender, arg, arg2, startCallbackIndex, callbackCount, 0);
}
/**
* Notify callbacks that have mRemainderRemoved bits set for remainderIndex. If
* remainderIndex is -1, the first 64 will be notified instead.
*
* @param sender The originator. This is an opaque parameter passed to
* {@link CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int, Object)}
* @param arg An opaque parameter passed to
* {@link CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int, Object)}
* @param arg2 An opaque parameter passed to
* {@link CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int, Object)}
* @param remainderIndex The index into mRemainderRemoved that should be notified.
*/
private void notifyRemainder(T sender, int arg, A arg2, int remainderIndex) {
if (remainderIndex < 0) {
notifyFirst64(sender, arg, arg2);
} else {
final long bits = mRemainderRemoved[remainderIndex];
final int startIndex = (remainderIndex + 1) * Long.SIZE;
final int endIndex = Math.min(mCallbacks.size(), startIndex + Long.SIZE);
notifyRemainder(sender, arg, arg2, remainderIndex - 1);
notifyCallbacks(sender, arg, arg2, startIndex, endIndex, bits);
}
}
/**
* Notify callbacks from startIndex to endIndex, using bits as the bit status
* for whether they have been removed or not. bits should be from mRemainderRemoved or
* mFirst64Removed. bits set to 0 indicates that all callbacks from startIndex to
* endIndex should be notified.
*
* @param sender The originator. This is an opaque parameter passed to
* {@link CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int, Object)}
* @param arg An opaque parameter passed to
* {@link CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int, Object)}
* @param arg2 An opaque parameter passed to
* {@link CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int, Object)}
* @param startIndex The index into the mCallbacks to start notifying.
* @param endIndex One past the last index into mCallbacks to notify.
* @param bits A bit field indicating which callbacks have been removed and shouldn't
* be notified.
*/
private void notifyCallbacks(T sender, int arg, A arg2, final int startIndex,
final int endIndex, final long bits) {
long bitMask = 1;
for (int i = startIndex; i < endIndex; i++) {
if ((bits & bitMask) == 0) {
mNotifier.onNotifyCallback(mCallbacks.get(i), sender, arg, arg2);
}
bitMask <<= 1;
}
}
这里的mNotifyer.notifyCallback其实就会调用到下面的PropertyChangeRegistry中定义的NOTIFYER_CALLBACK属性中的onNotifyCallback实现,而这里的callback其实就是WeakPropertyListener,因为WeakPropertyListener是OnPropertyChangedCallback的子类,这里会回调给mLocalFieldObservers数组中所有的WeakListener。
public class PropertyChangeRegistry extends
CallbackRegistry {
private static final CallbackRegistry.NotifierCallback NOTIFIER_CALLBACK = new CallbackRegistry.NotifierCallback() {
@Override
public void onNotifyCallback(Observable.OnPropertyChangedCallback callback, Observable sender,
int arg, Void notUsed) {
callback.onPropertyChanged(sender, arg);
}
};
public PropertyChangeRegistry() {
super(NOTIFIER_CALLBACK);
}
/**
* Notifies registered callbacks that a specific property has changed.
*
* @param observable The Observable that has changed.
* @param propertyId The BR id of the property that has changed or BR._all if the entire
* Observable has changed.
*/
public void notifyChange(@NonNull Observable observable, int propertyId) {
notifyCallbacks(observable, propertyId, null);
}
}
而这里的callback.onPropertyChanged(sender, arg);则会回调到ViewDataBinding类中的WeakPropertyListener.onPropertyChanged:
private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
implements ObservableReference {
final WeakListener mListener;
public WeakPropertyListener(ViewDataBinding binder, int localFieldId) {
mListener = new WeakListener(binder, localFieldId, this);
}
@Override
public WeakListener getListener() {
return mListener;
}
@Override
public void addListener(Observable target) {
target.addOnPropertyChangedCallback(this);
}
@Override
public void removeListener(Observable target) {
target.removeOnPropertyChangedCallback(this);
}
@Override
public void setLifecycleOwner(LifecycleOwner lifecycleOwner) {
}
@Override
public void onPropertyChanged(Observable sender, int propertyId) {
ViewDataBinding binder = mListener.getBinder();
if (binder == null) {
return;
}
Observable obj = mListener.getTarget();
if (obj != sender) {
return; // notification from the wrong object?
}
binder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId);
}
}
从mListener中取出target,而这里的mListener其实就是WeakListener,而每个被观察者,其实都 是有一个对应的LocalFieldId,这个id就是BR文件中定义中的id。
private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {
if (mInLiveDataRegisterObserver) {
// We're in LiveData registration, which always results in a field change
// that we can ignore. The value will be read immediately after anyway, so
// there is no need to be dirty.
return;
}
boolean result = onFieldChange(mLocalFieldId, object, fieldId);
if (result) {
requestRebind();
}
}
这里的handleFieldChange方法,在我们生成的ActivityMainBindingImpl也有实现:
@Override
protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {
switch (localFieldId) {
case 0 :
return onChangeUserName((androidx.databinding.ObservableField) object, fieldId);
case 1 :
return onChangeUserPwd((androidx.databinding.ObservableField) object, fieldId);
}
return false;
}
private boolean onChangeUserName(androidx.databinding.ObservableField UserName, int fieldId) {
if (fieldId == BR._all) {
synchronized(this) {
mDirtyFlags |= 0x1L;
}
return true;
}
return false;
}
private boolean onChangeUserPwd(androidx.databinding.ObservableField UserPwd, int fieldId) {
if (fieldId == BR._all) {
synchronized(this) {
mDirtyFlags |= 0x2L;
}
return true;
}
return false;
}
因为我们之前传入的localFieldId = 0,所以会返回true,即会返回到ViewDataBinding.java中的handleFieldChange方法,继续执行requestRebind():
private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {
if (mInLiveDataRegisterObserver) {
// We're in LiveData registration, which always results in a field change
// that we can ignore. The value will be read immediately after anyway, so
// there is no need to be dirty.
return;
}
boolean result = onFieldChange(mLocalFieldId, object, fieldId);
if (result) {
requestRebind();
}
}
protected void requestRebind() {
if (mContainingBinding != null) {
mContainingBinding.requestRebind();
} else {
final LifecycleOwner owner = this.mLifecycleOwner;
if (owner != null) {
Lifecycle.State state = owner.getLifecycle().getCurrentState();
if (!state.isAtLeast(Lifecycle.State.STARTED)) {
return; // wait until lifecycle owner is started
}
}
synchronized (this) {
if (mPendingRebind) {
return;
}
mPendingRebind = true;
}
if (USE_CHOREOGRAPHER) {
mChoreographer.postFrameCallback(mFrameCallback);
} else {
mUIThreadHandler.post(mRebindRunnable);
}
}
}
这里最终会通过mUIThreadHandler.post(mRebindRunnable);执行mRebindRunnable里面的run方法:
/**
* Runnable executed on animation heartbeat to rebind the dirty Views.
*/
private final Runnable mRebindRunnable = new Runnable() {
@Override
public void run() {
synchronized (this) {
mPendingRebind = false;
}
processReferenceQueue();
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
// Nested so that we don't get a lint warning in IntelliJ
if (!mRoot.isAttachedToWindow()) {
// Don't execute the pending bindings until the View
// is attached again.
mRoot.removeOnAttachStateChangeListener(ROOT_REATTACHED_LISTENER);
mRoot.addOnAttachStateChangeListener(ROOT_REATTACHED_LISTENER);
return;
}
}
executePendingBindings();
}
};
然后执行到executePendingBindings()方法,而方法的实现又是在我们生成的MainActivityBindingImpl里:
@Override
protected void executeBindings() {
long dirtyFlags = 0;
synchronized(this) {
dirtyFlags = mDirtyFlags;
mDirtyFlags = 0;
}
androidx.databinding.ObservableField userName = null;
java.lang.String userPwdGet = null;
com.yexing.databinding.User user = mUser;
java.lang.String userNameGet = null;
androidx.databinding.ObservableField userPwd = null;
if ((dirtyFlags & 0xfL) != 0) {
if ((dirtyFlags & 0xdL) != 0) {
if (user != null) {
// read user.name
userName = user.getName();
}
updateRegistration(0, userName);
if (userName != null) {
// read user.name.get()
userNameGet = userName.get();
}
}
if ((dirtyFlags & 0xeL) != 0) {
if (user != null) {
// read user.pwd
userPwd = user.getPwd();
}
updateRegistration(1, userPwd);
if (userPwd != null) {
// read user.pwd.get()
userPwdGet = userPwd.get();
}
}
}
// batch finished
if ((dirtyFlags & 0xdL) != 0) {
// api target 1
androidx.databinding.adapters.TextViewBindingAdapter.setText(this.mboundView1, userNameGet);
}
if ((dirtyFlags & 0xeL) != 0) {
// api target 1
androidx.databinding.adapters.TextViewBindingAdapter.setText(this.mboundView2, userPwdGet);
}
}
这个方法其实就是执行了setText *** 作,也就是调用了页面布局的View的setText把数据显示出来。到此,DataBinding的源码分析完成。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)