个人博客
http://www.milovetingting.cn
Jetpack学习-DataBinding 简单使用 在需要使用DataBinding的模块的build.gradle中增加
1 2 3 4 5 6 7 8 9 android { defaultConfig { dataBinding{ enabled true } } }
然后同步
新建一个继承自BaseObservable
的类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public class User extends BaseObservable { private String name; private int age; public User (String name, int age) { this .name = name; this .age = age; } @Bindable public String getName () { return name; } public void setName (String name) { this .name = name; notifyPropertyChanged(com.wangyz.jetpack.BR.name); } @Bindable public int getAge () { return age; } public void setAge (int age) { this .age = age; notifyPropertyChanged(com.wangyz.jetpack.BR.age); } }
在需要绑定的字段的get
方法上增加@Bindable
注解,在set方法里增加notifyPropertyChanged(com.wangyz.jetpack.BR.name)
build工程
新建布局文件,在布局最外层的节点上按alt+enter
,在弹出的选项中选择Convert to data binding layout
,布局就会转换成DataBinding格式的布局。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <?xml version="1.0" encoding="utf-8" ?> <layout xmlns:android ="http://schemas.android.com/apk/res/android" > <data > <variable name ="user" type ="com.wangyz.jetpack.databinding.User" /> </data > <LinearLayout android:layout_width ="match_parent" android:layout_height ="match_parent" android:orientation ="vertical" > <Button android:onClick ="update" android:text ="更新" android:layout_width ="match_parent" android:layout_height ="50dp" /> <TextView android:layout_width ="match_parent" android:layout_height ="50dp" android:gravity ="center_vertical" android:text ="@{user.name}" /> <TextView android:layout_width ="match_parent" android:layout_height ="50dp" android:gravity ="center_vertical" android:text ="@{String.valueOf(user.age)}" /> </LinearLayout > </layout >
转换后的布局,会将layout
作为最外层的节点,还会在里面增加一个data
节点。我们需要在这个data节点中增加variable
节点,并配置name
和type
属性。name命名随意,type输入前面定义的User
类。
对需要绑定的控件属性,如text赋值为@{user.name}
,意思是给text属性赋值为前面绑定的User类的name。这样当User的name发生改变时,控件的text属性就会自动改变。
在Activity中绑定User和布局
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class DataBindingActivity extends AppCompatActivity { User user; ActivityDatabindingBinding binding; @Override protected void onCreate (@Nullable Bundle savedInstanceState) { super .onCreate(savedInstanceState); binding = DataBindingUtil.setContentView(this , R.layout.activity_databinding); user = new User ("张三" , 18 ); binding.setUser(user); } public void update (View view) { user.setName(user.getName() + "$" ); user.setAge(user.getAge() + 1 ); binding.setVariable(com.wangyz.jetpack.BR.user, user); } }
通过DataBindingUtil.setContentView(this, R.layout.activity_databinding)
来绑定,并返回Binding
,然后通过Binding的setUser
方法,就可以给布局设置数据。
原理 布局文件 下面来看下原理。DataBinding相比前面的Lifecycle
和LiveData
要复杂。
我们将应用运行到手机上,这个在开发者看来是很简单的一件事,但是Android Studio却为我们做了很多事。
首先,布局文件会分为两个xml文件。
在app/buil/intermediates/data_binding_layout_info_type_merge/debug/mergeDebugResources/out/
目录下,可以看到生成了一个activity_databinding-layout.xml
文件,这个文件名称是在我们原来的布局名称后加上了-layout。它的内容如上图右侧所示。在最外层的节点里记录了对应的布局文件,然后通过定义Variables
节点,记录了对应的数据类。在Targets
节点中,记录了原布局的tag
,及使用了DataBinding的控件的tag,然后通过Expression
节点,记录对应的数据。
在app/build/intermediates/incremental/mergeDebugResources/stripped.dir/layout/
目录下,可以看到activity_databinding.xml
文件,这个文件就是我们原来的文件名,不过里面稍作了一些变动,增加了一些tag
,这些tag的值和前面的activity_databinding-layout.xml
记录的是对应的。
DataBindingUtil.setContentView 我们从DataBindingUtil.setContentView(this, R.layout.activity_databinding)
这个方法看起。
1 2 3 4 public static <T extends ViewDataBinding > T setContentView (@NonNull Activity activity, int layoutId) { return setContentView(activity, layoutId, sDefaultComponent); }
这个方法里又调用了setContentView
方法
1 2 3 4 5 6 7 public static <T extends ViewDataBinding > 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); }
这个方法里调用了bindToAddedViews
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 private static <T extends ViewDataBinding > 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); } }
然后调用bind
方法
1 2 3 4 static <T extends ViewDataBinding > T bind (DataBindingComponent bindingComponent, View root, int layoutId) { return (T) sMapper.getDataBinder(bindingComponent, root, layoutId); }
这里调用了sMapper
的getDataBinder
方法,sMapper其实就是自动生成的DataBinderMapperImpl
文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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_ACTIVITYDATABINDING: { if ("layout/activity_databinding_0" .equals(tag)) { return new ActivityDatabindingBindingImpl (component, view); } throw new IllegalArgumentException ("The tag for activity_databinding is invalid. Received: " + tag); } } } return null ; }
在这里调用了ActivityDatabindingBindingImpl
的构造方法
1 2 3 public ActivityDatabindingBindingImpl (@Nullable androidx.databinding.DataBindingComponent bindingComponent, @NonNull View root) { this (bindingComponent, root, mapBindings(bindingComponent, root, 3 , sIncludes, sViewsWithIds)); }
这里调用了ViewDataBinding
类mapBindings
方法
1 2 3 4 5 protected static Object[] mapBindings(DataBindingComponent bindingComponent, View root, int numBindings, ViewDataBinding.IncludedLayouts includes, SparseIntArray viewsWithIds) { Object[] bindings = new Object [numBindings]; mapBindings(bindingComponent, root, bindings, includes, viewsWithIds, true ); return bindings; }
这里调用mapBindings
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 private static void mapBindings (DataBindingComponent bindingComponent, View view, Object[] bindings, ViewDataBinding.IncludedLayouts includes, SparseIntArray viewsWithIds, boolean isRoot) { ViewDataBinding existingBinding = getBinding(view); if (existingBinding == null ) { Object objTag = view.getTag(); String tag = objTag instanceof String ? (String)objTag : null ; boolean isBound = false ; int indexInIncludes; int id; int count; if (isRoot && tag != null && tag.startsWith("layout" )) { id = tag.lastIndexOf(95 ); if (id > 0 && isNumeric(tag, id + 1 )) { count = parseTagInt(tag, id + 1 ); if (bindings[count] == null ) { bindings[count] = view; } indexInIncludes = includes == null ? -1 : count; isBound = true ; } else { indexInIncludes = -1 ; } } else if (tag != null && tag.startsWith("binding_" )) { id = parseTagInt(tag, BINDING_NUMBER_START); if (bindings[id] == null ) { bindings[id] = view; } isBound = true ; indexInIncludes = includes == null ? -1 : id; } else { indexInIncludes = -1 ; } if (!isBound) { id = view.getId(); if (id > 0 && viewsWithIds != null && (count = viewsWithIds.get(id, -1 )) >= 0 && bindings[count] == null ) { bindings[count] = view; } } if (view instanceof ViewGroup) { ViewGroup viewGroup = (ViewGroup)view; count = viewGroup.getChildCount(); int minInclude = 0 ; for (int i = 0 ; i < count; ++i) { View child = viewGroup.getChildAt(i); boolean isInclude = false ; if (indexInIncludes >= 0 && child.getTag() instanceof String) { String childTag = (String)child.getTag(); if (childTag.endsWith("_0" ) && childTag.startsWith("layout" ) && childTag.indexOf(47 ) > 0 ) { int includeIndex = findIncludeIndex(childTag, minInclude, includes, indexInIncludes); if (includeIndex >= 0 ) { isInclude = true ; minInclude = includeIndex + 1 ; int index = includes.indexes[indexInIncludes][includeIndex]; int layoutId = includes.layoutIds[indexInIncludes][includeIndex]; int lastMatchingIndex = findLastMatching(viewGroup, i); if (lastMatchingIndex == i) { bindings[index] = DataBindingUtil.bind(bindingComponent, child, layoutId); } else { int includeCount = lastMatchingIndex - i + 1 ; View[] included = new View [includeCount]; for (int j = 0 ; j < includeCount; ++j) { included[j] = viewGroup.getChildAt(i + j); } bindings[index] = DataBindingUtil.bind(bindingComponent, included, layoutId); i += includeCount - 1 ; } } } } if (!isInclude) { mapBindings(bindingComponent, child, bindings, includes, viewsWithIds, false ); } } } } }
这个方法其实就是解析前面的两个xml文件,将绑定的控件保存起来。
DataBindingUtil.setContentView
方法执行完成后,就可以获取到对应的DataBinding对象。
来一张简单的时序图
binding.setUser binding.setUser对应的是ActivityDatabindingBindingImpl的setUser方法
1 2 3 4 5 6 7 8 9 public void setUser (@Nullable com.wangyz.jetpack.databinding.User User) { updateRegistration(0 , User); this .mUser = User; synchronized (this ) { mDirtyFlags |= 0x1L ; } notifyPropertyChanged(BR.user); super .requestRebind(); }
updateRegistration 先来看updateRegistration
,这里就是注册过程。调用ViewDataBinding
的updateRegistration方法
1 2 3 protected boolean updateRegistration (int localFieldId, Observable observable) { return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER); }
然后调用updateRegistration
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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 ; } if (listener.getTarget() == observable) { return false ; } unregisterFrom(localFieldId); registerTo(localFieldId, observable, listenerCreator); return true ; }
调用registerTo
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 protected void registerTo (int localFieldId, Object observable, CreateWeakListener listenerCreator) { if (observable == null ) { return ; } WeakListener listener = mLocalFieldObservers[localFieldId]; if (listener == null ) { listener = listenerCreator.create(this , localFieldId); mLocalFieldObservers[localFieldId] = listener; if (mLifecycleOwner != null ) { listener.setLifecycleOwner(mLifecycleOwner); } } listener.setTarget(observable); }
这个方法将传进来的数据保存到WeakListener
中
notifyPropertyChanged 执行完成updateRegistration
方法后,需要执行notifyPropertyChanged方法,通知更新,这个方法在BaseObservable里
1 2 3 4 5 6 7 8 public void notifyPropertyChanged (int fieldId) { synchronized (this ) { if (mCallbacks == null ) { return ; } } mCallbacks.notifyCallbacks(this , fieldId, null ); }
然后调用CallbackRegistry
的notifyCallbacks
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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 ; } } }
这里调用了notifyRecurse
方法去递归通知
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 private void notifyRecurse (T sender, int arg, A arg2) { final int callbackCount = mCallbacks.size(); final int remainderIndex = mRemainderRemoved == null ? -1 : mRemainderRemoved.length - 1 ; notifyRemainder(sender, arg, arg2, remainderIndex); final int startCallbackIndex = (remainderIndex + 2 ) * Long.SIZE; notifyCallbacks(sender, arg, arg2, startCallbackIndex, callbackCount, 0 ); }
这个方法里调用notifyCallbacks
方法
1 2 3 4 5 6 7 8 9 10 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 ; } }
调用NotifierCallback
的onNotifyCallback
方法,它的具体回调在PropertyChangeRegistry
里
1 2 3 4 5 private static final NotifierCallback<OnPropertyChangedCallback, Observable, Void> NOTIFIER_CALLBACK = new NotifierCallback <OnPropertyChangedCallback, Observable, Void>() { public void onNotifyCallback (OnPropertyChangedCallback callback, Observable sender, int arg, Void notUsed) { callback.onPropertyChanged(sender, arg); } };
然后回调Observable
的内部类OnPropertyChangedCallback
的onPropertyChanged
方法,而这个方法的实现是ViewDataBinding
的内部类WeakPropertyListener
1 2 3 4 5 6 7 8 9 10 11 public void onPropertyChanged (Observable sender, int propertyId) { ViewDataBinding binder = mListener.getBinder(); if (binder == null ) { return ; } Observable obj = mListener.getTarget(); if (obj != sender) { return ; } binder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId); }
然后调用handleFieldChange
方法
1 2 3 4 5 6 7 8 9 10 11 12 private void handleFieldChange (int mLocalFieldId, Object object, int fieldId) { if (mInLiveDataRegisterObserver) { return ; } boolean result = onFieldChange(mLocalFieldId, object, fieldId); if (result) { requestRebind(); } }
调用onFieldChange
方法,它的具体实现是ActivityDatabindingBindingImpl
1 2 3 4 5 6 7 protected boolean onFieldChange (int localFieldId, Object object, int fieldId) { switch (localFieldId) { case 0 : return onChangeUser((com.wangyz.jetpack.databinding.User) object, fieldId); } return false ; }
调用onChangeUser
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 private boolean onChangeUser (com.wangyz.jetpack.databinding.User User, int fieldId) { if (fieldId == BR._all) { synchronized (this ) { mDirtyFlags |= 0x1L ; } return true ; } else if (fieldId == BR.name) { synchronized (this ) { mDirtyFlags |= 0x2L ; } return true ; } else if (fieldId == BR.age) { synchronized (this ) { mDirtyFlags |= 0x4L ; } return true ; } return false ; }
在执行完onFieldChange
方法后,会再执行requestRebind
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 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 ; } } synchronized (this ) { if (mPendingRebind) { return ; } mPendingRebind = true ; } if (USE_CHOREOGRAPHER) { mChoreographer.postFrameCallback(mFrameCallback); } else { mUIThreadHandler.post(mRebindRunnable); } } }
在这里post
了一个mRebindRunnable
到主线程中,看下mRebindRunnable
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 private final Runnable mRebindRunnable = new Runnable () { @Override public void run () { synchronized (this ) { mPendingRebind = false ; } processReferenceQueue(); if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) { if (!mRoot.isAttachedToWindow()) { mRoot.removeOnAttachStateChangeListener(ROOT_REATTACHED_LISTENER); mRoot.addOnAttachStateChangeListener(ROOT_REATTACHED_LISTENER); return ; } } executePendingBindings(); } };
在这个方法里执行了executePendingBindings
方法
1 2 3 4 5 6 7 public void executePendingBindings () { if (mContainingBinding == null ) { executeBindingsInternal(); } else { mContainingBinding.executePendingBindings(); } }
然后执行executeBindingsInternal
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 private void executeBindingsInternal () { if (mIsExecutingPendingBindings) { requestRebind(); return ; } if (!hasPendingBindings()) { return ; } mIsExecutingPendingBindings = true ; mRebindHalted = false ; if (mRebindCallbacks != null ) { mRebindCallbacks.notifyCallbacks(this , REBIND, null ); if (mRebindHalted) { mRebindCallbacks.notifyCallbacks(this , HALTED, null ); } } if (!mRebindHalted) { executeBindings(); if (mRebindCallbacks != null ) { mRebindCallbacks.notifyCallbacks(this , REBOUND, null ); } } mIsExecutingPendingBindings = false ; }
这个方法里执行了executeBindings
方法,它在实现是ActivityDatabindingBindingImpl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 protected void executeBindings () { long dirtyFlags = 0 ; synchronized (this ) { dirtyFlags = mDirtyFlags; mDirtyFlags = 0 ; } java.lang.String userName = null ; int userAge = 0 ; com.wangyz.jetpack.databinding.User user = mUser; java.lang.String stringValueOfUserAge = null ; if ((dirtyFlags & 0xfL ) != 0 ) { if ((dirtyFlags & 0xbL ) != 0 ) { if (user != null ) { userName = user.getName(); } } if ((dirtyFlags & 0xdL ) != 0 ) { if (user != null ) { userAge = user.getAge(); } stringValueOfUserAge = java.lang.String.valueOf(userAge); } } if ((dirtyFlags & 0xbL ) != 0 ) { androidx.databinding.adapters.TextViewBindingAdapter.setText(this .mboundView1, userName); } if ((dirtyFlags & 0xdL ) != 0 ) { androidx.databinding.adapters.TextViewBindingAdapter.setText(this .mboundView2, stringValueOfUserAge); } }
可以看到,是通过androidx.databinding.adapters.TextViewBindingAdapter.setText来实现的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public static void setText (TextView view, CharSequence text) { final CharSequence oldText = view.getText(); if (text == oldText || (text == null && oldText.length() == 0 )) { return ; } if (text instanceof Spanned) { if (text.equals(oldText)) { return ; } } else if (!haveContentsChanged(text, oldText)) { return ; } view.setText(text); }
这里我们界面就发生了变更。
来一张简单的时序图
setVariable 1 2 3 4 5 6 7 8 9 10 public boolean setVariable (int variableId, @Nullable Object variable) { boolean variableSet = true ; if (BR.user == variableId) { setUser((com.wangyz.jetpack.databinding.User) variable); } else { variableSet = false ; } return variableSet; }
最终还是通过setUser来实现的。