• databinding 一篇文章就够了


    使用篇

    首先找到app的build.gradle

    1. android {
    2. compileSdk 32
    3. defaultConfig {
    4. applicationId "com.example.myapplication"
    5. minSdk 24
    6. targetSdk 32
    7. versionCode 1
    8. versionName "1.0"
    9. testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    10. }
    11. buildTypes {
    12. release {
    13. minifyEnabled false
    14. proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    15. }
    16. }
    17. compileOptions {
    18. sourceCompatibility JavaVersion.VERSION_1_8
    19. targetCompatibility JavaVersion.VERSION_1_8
    20. }
    21. kotlinOptions {
    22. jvmTarget = '1.8'
    23. }
    24. //添加下面的配置
    25. dataBinding {
    26. enabled = true
    27. }
    28. }

    然后进xml文件,将我们的xml转成databinding布局:

    1. "1.0" encoding="utf-8"?>
    2. <layout xmlns:android="http://schemas.android.com/apk/res/android"
    3. xmlns:app="http://schemas.android.com/apk/res-auto"
    4. xmlns:tools="http://schemas.android.com/tools">
    5. <data>
    6. data>
    7. <androidx.constraintlayout.widget.ConstraintLayout
    8. android:layout_width="match_parent"
    9. android:layout_height="match_parent"
    10. tools:context=".MainActivity">
    11. <TextView
    12. android:layout_width="wrap_content"
    13. android:layout_height="wrap_content"
    14. android:text="Hello World!"
    15. app:layout_constraintBottom_toBottomOf="parent"
    16. app:layout_constraintLeft_toLeftOf="parent"
    17. app:layout_constraintRight_toRightOf="parent"
    18. app:layout_constraintTop_toTopOf="parent" />
    19. androidx.constraintlayout.widget.ConstraintLayout>
    20. layout>

    关于IDE自动转databinding布局的说明:将鼠标停在最外层的constraintLayout的布局的里面的空闲位置,然后同时按option+enter(Mac),就会出现convert to data binding layout提示。

    我们先写一个bean:

    1. package com.example.myapplication
    2. import androidx.annotation.Keep
    3. @Keep
    4. data class User(
    5. var userName: String,
    6. var passWord: String
    7. )

    然后布局这样写:

    1. "1.0" encoding="utf-8"?>
    2. <layout xmlns:android="http://schemas.android.com/apk/res/android"
    3. xmlns:app="http://schemas.android.com/apk/res-auto"
    4. xmlns:tools="http://schemas.android.com/tools">
    5. <data>
    6. <variable
    7. name="user"
    8. type="com.example.myapplication.User" />
    9. data>
    10. <androidx.constraintlayout.widget.ConstraintLayout
    11. android:layout_width="match_parent"
    12. android:layout_height="match_parent"
    13. tools:context=".MainActivity">
    14. <TextView
    15. android:layout_width="wrap_content"
    16. android:layout_height="wrap_content"
    17. android:text="@{user.userName}"
    18. app:layout_constraintBottom_toBottomOf="parent"
    19. app:layout_constraintLeft_toLeftOf="parent"
    20. app:layout_constraintRight_toRightOf="parent"
    21. app:layout_constraintTop_toTopOf="parent" />
    22. androidx.constraintlayout.widget.ConstraintLayout>
    23. layout>

    name是名称,可以随便写,一般最好与bean一致,type就是具体定义的类型。@{user.***}实现了数据的引用。

    MainActivity使用:

    1. package com.example.myapplication
    2. import androidx.appcompat.app.AppCompatActivity
    3. import android.os.Bundle
    4. import androidx.databinding.DataBindingUtil
    5. import com.example.myapplication.databinding.ActivityMainBinding
    6. class MainActivity : AppCompatActivity() {
    7. var activityMainBinding: ActivityMainBinding? = null
    8. override fun onCreate(savedInstanceState: Bundle?) {
    9. super.onCreate(savedInstanceState)
    10. //setContentView(R.layout.activity_main)
    11. activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
    12. val user = User("lzy", "123456")
    13. activityMainBinding?.user = user
    14. }
    15. }

    注意,原有的设置布局的方式要换成通过DataBindingUtil的方式。

    运行一把:

    这样就完成了最基本的databinding的使用了。那有些同学可能会说,这样很麻烦呀,使用databinding的优势在哪里呢?我们接着看:

    1. package com.example.myapplication
    2. import androidx.appcompat.app.AppCompatActivity
    3. import android.os.Bundle
    4. import androidx.databinding.DataBindingUtil
    5. import com.example.myapplication.databinding.ActivityMainBinding
    6. import java.lang.Thread.sleep
    7. class MainActivity : AppCompatActivity() {
    8. var activityMainBinding: ActivityMainBinding? = null
    9. override fun onCreate(savedInstanceState: Bundle?) {
    10. super.onCreate(savedInstanceState)
    11. //setContentView(R.layout.activity_main)
    12. activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
    13. val user = User("lzy", "123456")
    14. activityMainBinding?.user = user
    15. Thread {
    16. for (i in 0 until 100) {
    17. sleep(1000)
    18. user.userName = "lzy".plus(i)
    19. activityMainBinding?.user = user
    20. }
    21. }.start()
    22. }
    23. }

    我们看到的效果是这样的:

     每一秒钟,UI就会自动变化,我们只有一个TextView还不是很明显,如果我们有很多View,当数据类发生变化的时候,会自动驱动UI变化,这样会使代码更加简洁,我们就不需要每一个View都去设置数据了。

    更进一步,我们还可以定义这样一个Bean类:

    1. package com.example.myapplication;
    2. import androidx.annotation.Keep;
    3. import androidx.databinding.BaseObservable;
    4. import androidx.databinding.Bindable;
    5. @Keep
    6. public class User2 extends BaseObservable {
    7. private String userName;
    8. private String passWord;
    9. @Bindable
    10. public String getUserName() {
    11. return userName;
    12. }
    13. public void setUserName(String userName) {
    14. this.userName = userName;
    15. notifyPropertyChanged(BR.userName);
    16. }
    17. @Bindable
    18. public String getPassWord() {
    19. return passWord;
    20. }
    21. public void setPassWord(String passWord) {
    22. this.passWord = passWord;
    23. notifyPropertyChanged(BR.passWord);
    24. }
    25. }

    使用:

    1. package com.example.myapplication
    2. import androidx.appcompat.app.AppCompatActivity
    3. import android.os.Bundle
    4. import androidx.databinding.DataBindingUtil
    5. import com.example.myapplication.databinding.ActivityMainBinding
    6. import java.lang.Thread.sleep
    7. class MainActivity : AppCompatActivity() {
    8. private var activityMainBinding: ActivityMainBinding? = null
    9. override fun onCreate(savedInstanceState: Bundle?) {
    10. super.onCreate(savedInstanceState)
    11. activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
    12. //val user = User("lzy", "123456")
    13. val user = User2()
    14. user.userName = "lzy2"
    15. user.passWord = "123456789"
    16. activityMainBinding?.user = user
    17. Thread {
    18. for (i in 0 until 100) {
    19. sleep(1000)
    20. user.userName = "lzy".plus(i)
    21. }
    22. }.start()
    23. }
    24. }

    我们发现User2继承BaseObservable后,并且使用notifyPropertyChanged后,数据变动自动触发UI变化。

    原理篇

    同其他Jetpack组件一样,databinding的使用也是一如既往的简单,但是只会使用是远远不够的,我们必须掌握其中的原理。

    我们首先关注XML文件,我们写的XML文件会通过databinding自动转成另外两个文件:

    文件1:

    app/build/intermediates/data_binding_layout_info_type_merge/debug/out/activity_main-layout.xml

    1. "1.0" encoding="utf-8" standalone="yes"?>
    2. <Layout directory="layout" filePath="app/src/main/res/layout/activity_main.xml"
    3. isBindingData="true" isMerge="false" layout="activity_main"
    4. modulePackage="com.example.myapplication" rootNodeType="androidx.constraintlayout.widget.ConstraintLayout">
    5. <Variables name="user" declared="true" type="com.example.myapplication.User2">
    6. <location endLine="9" endOffset="52" startLine="7" startOffset="8" />
    7. Variables>
    8. <Targets>
    9. <Target tag="layout/activity_main_0"
    10. view="androidx.constraintlayout.widget.ConstraintLayout">
    11. <Expressions />
    12. <location endLine="27" endOffset="55" startLine="13" startOffset="4" />
    13. Target>
    14. <Target tag="binding_1" view="TextView">
    15. <Expressions>
    16. <Expression attribute="android:text" text="user.userName">
    17. <Location endLine="21" endOffset="42" startLine="21" startOffset="12" />
    18. <TwoWay>falseTwoWay>
    19. <ValueLocation endLine="21" endOffset="40" startLine="21" startOffset="28" />
    20. Expression>
    21. Expressions>
    22. <location endLine="25" endOffset="55" startLine="18" startOffset="8" />
    23. Target>
    24. Targets>
    25. Layout>

    注:Targets里面有两个Target元素,后面会用到。

    文件2:

    app/build/intermediates/incremental/mergeDebugResources/stripped.dir/layout/activity_main.xml

    1. "1.0" encoding="utf-8"?>
    2. <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    3. xmlns:app="http://schemas.android.com/apk/res-auto"
    4. xmlns:tools="http://schemas.android.com/tools"
    5. android:layout_width="match_parent"
    6. android:layout_height="match_parent"
    7. android:tag="layout/activity_main_0"
    8. tools:context=".MainActivity">
    9. <TextView
    10. android:layout_width="wrap_content"
    11. android:layout_height="wrap_content"
    12. android:tag="binding_1"
    13. app:layout_constraintBottom_toBottomOf="parent"
    14. app:layout_constraintLeft_toLeftOf="parent"
    15. app:layout_constraintRight_toRightOf="parent"
    16. app:layout_constraintTop_toTopOf="parent" />
    17. androidx.constraintlayout.widget.ConstraintLayout>

    我们来看看setContentView到底做了什么?

    1. public static extends ViewDataBinding> T setContentView(@NonNull Activity activity,
    2. int layoutId) {
    3. return setContentView(activity, layoutId, sDefaultComponent);
    4. }
    5. public static extends ViewDataBinding> T setContentView(@NonNull Activity activity,
    6. int layoutId, @Nullable DataBindingComponent bindingComponent) {
    7. activity.setContentView(layoutId);
    8. View decorView = activity.getWindow().getDecorView();
    9. ViewGroup contentView = (ViewGroup) decorView.findViewById(android.R.id.content);
    10. return bindToAddedViews(bindingComponent, contentView, 0, layoutId);//1
    11. }

     我们关注注释1:

    1. private static extends ViewDataBinding> T bindToAddedViews(DataBindingComponent component,
    2. ViewGroup parent, int startChildren, int layoutId) {
    3. final int endChildren = parent.getChildCount();
    4. final int childrenAdded = endChildren - startChildren;
    5. if (childrenAdded == 1) {
    6. final View childView = parent.getChildAt(endChildren - 1);
    7. return bind(component, childView, layoutId);
    8. } else {
    9. final View[] children = new View[childrenAdded];
    10. for (int i = 0; i < childrenAdded; i++) {
    11. children[i] = parent.getChildAt(i + startChildren);
    12. }
    13. return bind(component, children, layoutId);//1
    14. }
    15. }

    再来看bind方法:

    1. static extends ViewDataBinding> T bind(DataBindingComponent bindingComponent, View[] roots,
    2. int layoutId) {
    3. return (T) sMapper.getDataBinder(bindingComponent, roots, layoutId);
    4. }

    sMapper又是个什么东西呢?

    private static DataBinderMapper sMapper = new DataBinderMapperImpl();

    我们再进DataBinderMapperImpl里面看看:

    1. public class DataBinderMapperImpl extends MergedDataBinderMapper {
    2. DataBinderMapperImpl() {
    3. addMapper(new com.example.myapplication.DataBinderMapperImpl());//1
    4. }
    5. }

    注释1处点进去看看:

    1. @Override
    2. public ViewDataBinding getDataBinder(DataBindingComponent component, View view, int layoutId) {
    3. int localizedLayoutId = INTERNAL_LAYOUT_ID_LOOKUP.get(layoutId);
    4. if(localizedLayoutId > 0) {
    5. final Object tag = view.getTag();
    6. if(tag == null) {
    7. throw new RuntimeException("view must have a tag");
    8. }
    9. switch(localizedLayoutId) {
    10. case LAYOUT_ACTIVITYMAIN: {
    11. if ("layout/activity_main_0".equals(tag)) {//1
    12. return new ActivityMainBindingImpl(component, view);//2
    13. }
    14. throw new IllegalArgumentException("The tag for activity_main is invalid. Received: " + tag);
    15. }
    16. }
    17. }
    18. return null;
    19. }

    我们前面知道外层tag为activity_main_0,所以注意注释2处。

    1. public ActivityMainBindingImpl(@Nullable androidx.databinding.DataBindingComponent bindingComponent, @NonNull View root) {
    2. this(bindingComponent, root, mapBindings(bindingComponent, root, 2, sIncludes, sViewsWithIds));
    3. }
    4. private ActivityMainBindingImpl(androidx.databinding.DataBindingComponent bindingComponent, View root, Object[] bindings) {
    5. super(bindingComponent, root, 1
    6. );
    7. this.mboundView0 = (androidx.constraintlayout.widget.ConstraintLayout) bindings[0];//1
    8. this.mboundView0.setTag(null);
    9. this.mboundView1 = (android.widget.TextView) bindings[1];//2
    10. this.mboundView1.setTag(null);
    11. setRootTag(root);
    12. // listeners
    13. invalidateAll();
    14. }

    我们来看注释1和注释2,这两个View保存在了ActivityMainBindingImpl里面,而:

    ActivityMainBindingImpl extends ActivityMainBinding

    所以:

    1. private var activityMainBinding: ActivityMainBinding? = null
    2. activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)

    DataBindingUtil.setContentView最终返回的activityMainBinding实际上是一个ActivityMainBindingImpl对象。

    我们再来看:

    activityMainBinding?.user = user

    点进去,发现直接点击了布局里面,那我们直接去看ActivityMainBindingImpl的setUser方法:

    1. public void setUser(@Nullable com.example.myapplication.User2 User) {
    2. updateRegistration(0, User);//1
    3. this.mUser = User;//2
    4. synchronized(this) {
    5. mDirtyFlags |= 0x1L;
    6. }
    7. notifyPropertyChanged(BR.user);
    8. super.requestRebind();
    9. }

    我们先来看注释2处,可见ActivityMainBindingImpl里面保存了User对象。接着点进注释1接着看:

    1. protected boolean updateRegistration(int localFieldId, Observable observable) {
    2. return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER);
    3. }

    CREATE_PROPERTY_LISTENER先标记一下,再进去看:

    1. protected boolean updateRegistration(int localFieldId, Object observable,
    2. CreateWeakListener listenerCreator) {
    3. if (observable == null) {
    4. return unregisterFrom(localFieldId);
    5. }
    6. WeakListener listener = mLocalFieldObservers[localFieldId];//1
    7. if (listener == null) {
    8. registerTo(localFieldId, observable, listenerCreator);//2
    9. return true;
    10. }
    11. if (listener.getTarget() == observable) {
    12. return false;//nothing to do, same object
    13. }
    14. unregisterFrom(localFieldId);
    15. registerTo(localFieldId, observable, listenerCreator);
    16. return true;
    17. }

    一开始走注释1处,得到的listener为null,然后走注释2处:

    1. protected void registerTo(int localFieldId, Object observable,
    2. CreateWeakListener listenerCreator) {
    3. if (observable == null) {
    4. return;
    5. }
    6. WeakListener listener = mLocalFieldObservers[localFieldId];
    7. if (listener == null) {
    8. listener = listenerCreator.create(this, localFieldId, sReferenceQueue);
    9. mLocalFieldObservers[localFieldId] = listener;//1
    10. if (mLifecycleOwner != null) {
    11. listener.setLifecycleOwner(mLifecycleOwner);
    12. }
    13. }
    14. listener.setTarget(observable);//2
    15. }

    注释1处很好理解,将listener保存在mLocalFieldObservers里面。然后再将被观察者User作为target传给注释2处。

    1. public void setTarget(T object) {
    2. unregister();
    3. mTarget = object;
    4. if (mTarget != null) {
    5. mObservable.addListener(mTarget);
    6. }
    7. }

    问题来了:mObservable是啥?我们再来看:

    1. private static final CreateWeakListener CREATE_PROPERTY_LISTENER = new CreateWeakListener() {
    2. @Override
    3. public WeakListener create(
    4. ViewDataBinding viewDataBinding,
    5. int localFieldId,
    6. ReferenceQueue referenceQueue
    7. ) {
    8. return new WeakPropertyListener(viewDataBinding, localFieldId, referenceQueue)
    9. .getListener();
    10. }
    11. };
    1. public WeakPropertyListener(
    2. ViewDataBinding binder,
    3. int localFieldId,
    4. ReferenceQueue referenceQueue
    5. ) {
    6. mListener = new WeakListener(binder, localFieldId, this, referenceQueue);
    7. }
    1. public WeakListener(
    2. ViewDataBinding binder,
    3. int localFieldId,
    4. ObservableReference observable,
    5. ReferenceQueue referenceQueue
    6. ) {
    7. super(binder, referenceQueue);
    8. mLocalFieldId = localFieldId;
    9. mObservable = observable;//1
    10. }

    这个mObservable就是WeakPropertyListener。我们来看它的addListener方法:

    1. private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
    2. implements ObservableReference {
    3. final WeakListener mListener;
    4. public WeakPropertyListener(
    5. ViewDataBinding binder,
    6. int localFieldId,
    7. ReferenceQueue referenceQueue
    8. ) {
    9. mListener = new WeakListener(binder, localFieldId, this, referenceQueue);
    10. }
    11. @Override
    12. public WeakListener getListener() {
    13. return mListener;
    14. }
    15. @Override
    16. public void addListener(Observable target) {
    17. target.addOnPropertyChangedCallback(this);//1
    18. }
    19. @Override
    20. public void removeListener(Observable target) {
    21. target.removeOnPropertyChangedCallback(this);
    22. }
    23. @Override
    24. public void setLifecycleOwner(LifecycleOwner lifecycleOwner) {
    25. }
    26. @Override
    27. public void onPropertyChanged(Observable sender, int propertyId) {
    28. ViewDataBinding binder = mListener.getBinder();
    29. if (binder == null) {
    30. return;
    31. }
    32. Observable obj = mListener.getTarget();
    33. if (obj != sender) {
    34. return; // notification from the wrong object?
    35. }
    36. binder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId);
    37. }
    38. }

    这里的target就是被观察者User2,我们进注释1看一下(User2继承了BaseObservable):

    1. public class BaseObservable implements Observable {
    2. private transient PropertyChangeRegistry mCallbacks;
    3. public BaseObservable() {
    4. }
    5. @Override
    6. public void addOnPropertyChangedCallback(@NonNull OnPropertyChangedCallback callback) {
    7. synchronized (this) {
    8. if (mCallbacks == null) {
    9. mCallbacks = new PropertyChangeRegistry();//后面会用到
    10. }
    11. }
    12. mCallbacks.add(callback);//1
    13. }
    14. @Override
    15. public void removeOnPropertyChangedCallback(@NonNull OnPropertyChangedCallback callback) {
    16. synchronized (this) {
    17. if (mCallbacks == null) {
    18. return;
    19. }
    20. }
    21. mCallbacks.remove(callback);
    22. }
    23. /**
    24. * Notifies listeners that all properties of this instance have changed.
    25. */
    26. public void notifyChange() {
    27. synchronized (this) {
    28. if (mCallbacks == null) {
    29. return;
    30. }
    31. }
    32. mCallbacks.notifyCallbacks(this, 0, null);
    33. }
    34. /**
    35. * Notifies listeners that a specific property has changed. The getter for the property
    36. * that changes should be marked with {@link Bindable} to generate a field in
    37. * BR to be used as fieldId.
    38. *
    39. * @param fieldId The generated BR id for the Bindable field.
    40. */
    41. public void notifyPropertyChanged(int fieldId) {
    42. synchronized (this) {
    43. if (mCallbacks == null) {
    44. return;
    45. }
    46. }
    47. mCallbacks.notifyCallbacks(this, fieldId, null);
    48. }
    49. }

    注释1处将listener加到一个集合里面。我们接着看:

    1. public void setUser(@Nullable com.example.myapplication.User2 User) {
    2. updateRegistration(0, User);
    3. this.mUser = User;
    4. synchronized(this) {
    5. mDirtyFlags |= 0x1L;
    6. }
    7. notifyPropertyChanged(BR.user);//1
    8. super.requestRebind();
    9. }

    进注释1:

    1. public void notifyPropertyChanged(int fieldId) {
    2. synchronized (this) {
    3. if (mCallbacks == null) {
    4. return;
    5. }
    6. }
    7. mCallbacks.notifyCallbacks(this, fieldId, null);//1
    8. }

    接着进去:

    1. public synchronized void notifyCallbacks(T sender, int arg, A arg2) {
    2. mNotificationLevel++;
    3. notifyRecurse(sender, arg, arg2);//1
    4. mNotificationLevel--;
    5. if (mNotificationLevel == 0) {
    6. if (mRemainderRemoved != null) {
    7. for (int i = mRemainderRemoved.length - 1; i >= 0; i--) {
    8. final long removedBits = mRemainderRemoved[i];
    9. if (removedBits != 0) {
    10. removeRemovedCallbacks((i + 1) * Long.SIZE, removedBits);
    11. mRemainderRemoved[i] = 0;
    12. }
    13. }
    14. }
    15. if (mFirst64Removed != 0) {
    16. removeRemovedCallbacks(0, mFirst64Removed);
    17. mFirst64Removed = 0;
    18. }
    19. }
    20. }

    接着进注释1:

    1. private void notifyRecurse(T sender, int arg, A arg2) {
    2. final int callbackCount = mCallbacks.size();
    3. final int remainderIndex = mRemainderRemoved == null ? -1 : mRemainderRemoved.length - 1;
    4. // Now we've got all callbakcs that have no mRemainderRemoved value, so notify the
    5. // others.
    6. notifyRemainder(sender, arg, arg2, remainderIndex);
    7. // notifyRemainder notifies all at maxIndex, so we'd normally start at maxIndex + 1
    8. // However, we must also keep track of those in mFirst64Removed, so we add 2 instead:
    9. final int startCallbackIndex = (remainderIndex + 2) * Long.SIZE;
    10. // The remaining have no bit set
    11. notifyCallbacks(sender, arg, arg2, startCallbackIndex, callbackCount, 0);//1
    12. }

    进注释1再看:

    1. private void notifyCallbacks(T sender, int arg, A arg2, final int startIndex,
    2. final int endIndex, final long bits) {
    3. long bitMask = 1;
    4. for (int i = startIndex; i < endIndex; i++) {
    5. if ((bits & bitMask) == 0) {
    6. mNotifier.onNotifyCallback(mCallbacks.get(i), sender, arg, arg2);//1
    7. }
    8. bitMask <<= 1;
    9. }
    10. }
    1. public class PropertyChangeRegistry extends
    2. CallbackRegistry {
    3. private static final CallbackRegistry.NotifierCallback NOTIFIER_CALLBACK = new CallbackRegistry.NotifierCallback() {
    4. @Override
    5. public void onNotifyCallback(Observable.OnPropertyChangedCallback callback, Observable sender,
    6. int arg, Void notUsed) {
    7. callback.onPropertyChanged(sender, arg);//1
    8. }
    9. };
    10. public PropertyChangeRegistry() {
    11. super(NOTIFIER_CALLBACK);
    12. }
    13. /**
    14. * Notifies registered callbacks that a specific property has changed.
    15. *
    16. * @param observable The Observable that has changed.
    17. * @param propertyId The BR id of the property that has changed or BR._all if the entire
    18. * Observable has changed.
    19. */
    20. public void notifyChange(@NonNull Observable observable, int propertyId) {
    21. notifyCallbacks(observable, propertyId, null);
    22. }
    23. }

    注意注释1处:

    1. private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
    2. implements ObservableReference {
    3. final WeakListener mListener;
    4. public WeakPropertyListener(
    5. ViewDataBinding binder,
    6. int localFieldId,
    7. ReferenceQueue referenceQueue
    8. ) {
    9. mListener = new WeakListener(binder, localFieldId, this, referenceQueue);
    10. }
    11. @Override
    12. public WeakListener getListener() {
    13. return mListener;
    14. }
    15. @Override
    16. public void addListener(Observable target) {
    17. target.addOnPropertyChangedCallback(this);
    18. }
    19. @Override
    20. public void removeListener(Observable target) {
    21. target.removeOnPropertyChangedCallback(this);
    22. }
    23. @Override
    24. public void setLifecycleOwner(LifecycleOwner lifecycleOwner) {
    25. }
    26. @Override
    27. public void onPropertyChanged(Observable sender, int propertyId) {
    28. ViewDataBinding binder = mListener.getBinder();
    29. if (binder == null) {
    30. return;
    31. }
    32. Observable obj = mListener.getTarget();
    33. if (obj != sender) {
    34. return; // notification from the wrong object?
    35. }
    36. binder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId);//1
    37. }
    38. }

    又回调回了listener!进注释1处看看:

    1. protected void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {
    2. if (mInLiveDataRegisterObserver || mInStateFlowRegisterObserver) {
    3. // We're in LiveData or StateFlow registration, which always results in a field change
    4. // that we can ignore. The value will be read immediately after anyway, so
    5. // there is no need to be dirty.
    6. return;
    7. }
    8. boolean result = onFieldChange(mLocalFieldId, object, fieldId);//1
    9. if (result) {
    10. requestRebind();
    11. }
    12. }

    再进注释1,在ActivityMainBindingImpl里面实现:

    1. @Override
    2. protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {
    3. switch (localFieldId) {
    4. case 0 :
    5. return onChangeUser((com.example.myapplication.User2) object, fieldId);
    6. }
    7. return false;
    8. }
    9. private boolean onChangeUser(com.example.myapplication.User2 User, int fieldId) {
    10. if (fieldId == BR._all) {
    11. synchronized(this) {
    12. mDirtyFlags |= 0x1L;
    13. }
    14. return true;
    15. }
    16. else if (fieldId == BR.userName) {
    17. synchronized(this) {
    18. mDirtyFlags |= 0x2L;
    19. }
    20. return true;
    21. }
    22. return false;
    23. }

    如果有变动,返回true,执行requestRebind():

    1. protected void requestRebind() {
    2. if (mContainingBinding != null) {
    3. mContainingBinding.requestRebind();
    4. } else {
    5. final LifecycleOwner owner = this.mLifecycleOwner;
    6. if (owner != null) {
    7. Lifecycle.State state = owner.getLifecycle().getCurrentState();
    8. if (!state.isAtLeast(Lifecycle.State.STARTED)) {
    9. return; // wait until lifecycle owner is started
    10. }
    11. }
    12. synchronized (this) {
    13. if (mPendingRebind) {
    14. return;
    15. }
    16. mPendingRebind = true;
    17. }
    18. if (USE_CHOREOGRAPHER) {
    19. mChoreographer.postFrameCallback(mFrameCallback);
    20. } else {
    21. mUIThreadHandler.post(mRebindRunnable);//1
    22. }
    23. }
    24. }

    注释1处,切换到主线程:

    1. private final Runnable mRebindRunnable = new Runnable() {
    2. @Override
    3. public void run() {
    4. synchronized (this) {
    5. mPendingRebind = false;
    6. }
    7. processReferenceQueue();
    8. if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
    9. // Nested so that we don't get a lint warning in IntelliJ
    10. if (!mRoot.isAttachedToWindow()) {
    11. // Don't execute the pending bindings until the View
    12. // is attached again.
    13. mRoot.removeOnAttachStateChangeListener(ROOT_REATTACHED_LISTENER);
    14. mRoot.addOnAttachStateChangeListener(ROOT_REATTACHED_LISTENER);
    15. return;
    16. }
    17. }
    18. executePendingBindings();//1
    19. }
    20. };

    进注释1:

    1. public void executePendingBindings() {
    2. if (mContainingBinding == null) {
    3. executeBindingsInternal();//1
    4. } else {
    5. mContainingBinding.executePendingBindings();
    6. }
    7. }

    再进注释1:

    1. private void executeBindingsInternal() {
    2. if (mIsExecutingPendingBindings) {
    3. requestRebind();
    4. return;
    5. }
    6. if (!hasPendingBindings()) {
    7. return;
    8. }
    9. mIsExecutingPendingBindings = true;
    10. mRebindHalted = false;
    11. if (mRebindCallbacks != null) {
    12. mRebindCallbacks.notifyCallbacks(this, REBIND, null);
    13. // The onRebindListeners will change mPendingHalted
    14. if (mRebindHalted) {
    15. mRebindCallbacks.notifyCallbacks(this, HALTED, null);
    16. }
    17. }
    18. if (!mRebindHalted) {
    19. executeBindings();//1
    20. if (mRebindCallbacks != null) {
    21. mRebindCallbacks.notifyCallbacks(this, REBOUND, null);
    22. }
    23. }
    24. mIsExecutingPendingBindings = false;
    25. }

    进注释1(ActivityMainBindingImpl实现):

    1. @Override
    2. protected void executeBindings() {
    3. long dirtyFlags = 0;
    4. synchronized(this) {
    5. dirtyFlags = mDirtyFlags;
    6. mDirtyFlags = 0;
    7. }
    8. com.example.myapplication.User2 user = mUser;
    9. java.lang.String userUserName = null;
    10. if ((dirtyFlags & 0x7L) != 0) {
    11. if (user != null) {
    12. // read user.userName
    13. userUserName = user.getUserName();
    14. }
    15. }
    16. // batch finished
    17. if ((dirtyFlags & 0x7L) != 0) {
    18. // api target 1
    19. androidx.databinding.adapters.TextViewBindingAdapter.setText(this.mboundView1, userUserName);//1
    20. }
    21. }

    this.mboundView1是前面保存textView引用的地方,我们再看注释1:

    1. public static void setText(TextView view, CharSequence text) {
    2. final CharSequence oldText = view.getText();
    3. if (text == oldText || (text == null && oldText.length() == 0)) {
    4. return;
    5. }
    6. if (text instanceof Spanned) {
    7. if (text.equals(oldText)) {
    8. return; // No change in the spans, so don't set anything.
    9. }
    10. } else if (!haveContentsChanged(text, oldText)) {
    11. return; // No content changes, so don't set anything.
    12. }
    13. view.setText(text);//1
    14. }

    本质上也是给TextView设置text。

  • 相关阅读:
    JVM学习(宋红康)之堆空间概述
    Unity代码设置锚点
    【JavaScript】巩固JS开发中十个常用功能/案例(11-20)
    rollback-only异常令我对事务有了新的认识
    使用 MyBatis 操作 Nebula Graph 的实践
    uni-app 5小时快速入门 5 目录结构
    MySQL主从复制(读写分离)
    测试工程师如何帮助开发域的质量变好
    MySQL8重置root账户密码图文教程
    为什么弹幕可以不挡人物?怎么实现的?Python带你来实现。
  • 原文地址:https://blog.csdn.net/qq_36428821/article/details/126650540