DataBinding源码分析

一、前言

在编译阶段,DataBinding会介入,扫描所有 res/layout/ 下的所有布局文件,然后为其生成相应的 ViewBinding 抽象类和实现类。
注:<androidx.databinding:databinding-compiler:版本号>与 <com.android.tools.build:gradle:版本号>一致

我们一般会在 Activity.onCreate 方法中,使用 DataBindingUtil.setContentView 来返回 ViewBinding 对象实例:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = DataBindingUtil.setContentView<ActivityMainBinding>(
                this, R.layout.activity_main)
    }
}

ActivityMainBinding 其实就是 layout 的 ViewBinding 类,它是通过 APT / KAPT 注解生成出来的抽象类,通常在

build/generated/data_binding_base_class_source_out/<环境>/dataBindingGenBaseClassesDebug/out/<包名>/databinding/......
  • 例如:ActivityMainBinding
public abstract class ActivityMainBinding extends ViewDataBinding {
    // layout.xml 中有多少控件,这里就会列举出来,无论是否需要绑定 model 中的属性
    @NonNull
    public final EditText name;
    @NonNull
    public final EditText pswd;
    @NonNull
    public final TextView text;

    @Bindable
    protected User mUser;  // 绑定的 Model

    protected ActivityMainBinding(Object _bindingComponent, View _root, int _localFieldCount,
                                  EditText name, EditText pswd, TextView text) {
        super(_bindingComponent, _root, _localFieldCount);
        this.name = name;
        this.pswd = pswd;
        this.text = text;
    }

    public abstract void setUser(@Nullable User user);

    @Nullable
    public User getUser() {
        return mUser;
    }

    @NonNull
    public static ActivityMainBinding inflate(@NonNull LayoutInflater inflater,
                                              @Nullable ViewGroup root, boolean attachToRoot) {
        return inflate(inflater, root, attachToRoot, DataBindingUtil.getDefaultComponent());
    }

    // 过滤掉 Deprecated 代码
    ......

    @NonNull
    public static ActivityMainBinding inflate(@NonNull LayoutInflater inflater) {
        return inflate(inflater, DataBindingUtil.getDefaultComponent());
    }

    public static ActivityMainBinding bind(@NonNull View view) {
        return bind(view, DataBindingUtil.getDefaultComponent());
    }

    // 过滤掉 Deprecated 代码
    ......
}

ActivityMainBinding 的实现类在

build/generated/source/kapt/<环境>/<包名>/databinding/......
  • ActivityMainBindingImpl
import <包名>.BR; // build/generated/source/kapt/<环境>/<包名>/BR.java

public class ActivityMainBindingImpl extends ActivityMainBinding {

    @Nullable
    private static final androidx.databinding.ViewDataBinding.IncludedLayouts sIncludes;
    @Nullable
    private static final android.util.SparseIntArray sViewsWithIds;

    static {
        sIncludes = null;
        sViewsWithIds = null;
    }

    // views
    @NonNull
    private final androidx.constraintlayout.widget.ConstraintLayout mboundView0;
    // variables
    // values
    // listeners
    // Inverse Binding Event Handlers
    private androidx.databinding.InverseBindingListener nameandroidTextAttrChanged = new androidx.databinding.InverseBindingListener() {
        @Override
        public void onChange() {
            // Inverse of user.name
            //         is user.setName((java.lang.String) callbackArg_0)
            java.lang.String callbackArg_0 = androidx.databinding.adapters.TextViewBindingAdapter.getTextString(name);
            // localize variables for thread safety
            // user.name
            java.lang.String userName = null;
            // user != null
            boolean userJavaLangObjectNull = false;
            // user
            com.demo.study.model.User user = mUser;


            userJavaLangObjectNull = (user) != (null);
            if (userJavaLangObjectNull) {


                user.setName(((java.lang.String) (callbackArg_0)));
            }
        }
    };

    public ActivityMainBindingImpl(@Nullable androidx.databinding.DataBindingComponent bindingComponent, @NonNull View root) {
        this(bindingComponent, root, mapBindings(bindingComponent, root, 3, sIncludes, sViewsWithIds));
    }

    private ActivityMainBindingImpl(androidx.databinding.DataBindingComponent bindingComponent, View root, Object[] bindings) {
        super(bindingComponent, root, 1
                , (android.widget.EditText) bindings[2]
                , (android.widget.TextView) bindings[1]
        );
        this.mboundView0 = (androidx.constraintlayout.widget.ConstraintLayout) bindings[0];
        this.mboundView0.setTag(null);
        this.name.setTag(null);
        this.text.setTag(null);
        setRootTag(root);
        // listeners
        invalidateAll();
    }

    @Override
    public void invalidateAll() {
        synchronized (this) {
            mDirtyFlags = 0x8L;
        }
        requestRebind();
    }

    @Override
    public boolean hasPendingBindings() {
        synchronized (this) {
            if (mDirtyFlags != 0) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean setVariable(int variableId, @Nullable Object variable) {
        boolean variableSet = true;
        if (BR.user == variableId) {
            setUser((com.demo.study.model.User) variable);
        } else {
            variableSet = false;
        }
        return variableSet;
    }

    public void setUser(@Nullable com.demo.study.model.User User) {
        updateRegistration(0, User);
        this.mUser = User;
        synchronized (this) {
            mDirtyFlags |= 0x1L;
        }
        notifyPropertyChanged(BR.user);
        super.requestRebind();
    }

    @Override
    protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {
        switch (localFieldId) {
            case 0:
                return onChangeUser((com.demo.study.model.User) object, fieldId);
        }
        return false;
    }

    private boolean onChangeUser(com.demo.study.model.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.password) {
            synchronized (this) {
                mDirtyFlags |= 0x4L;
            }
            return true;
        }
        return false;
    }

    @Override
    protected void executeBindings() {
        long dirtyFlags = 0;
        synchronized (this) {
            dirtyFlags = mDirtyFlags;
            mDirtyFlags = 0;
        }
        java.lang.String userName = null;
        com.demo.study.model.User user = mUser;
        java.lang.String userNameCharUserPassword = null;
        java.lang.String userNameChar = null;
        java.lang.String userPassword = null;

        if ((dirtyFlags & 0xfL) != 0) {
            if (user != null) {
                // read user.name
                userName = user.getName();
                // read user.password
                userPassword = user.getPassword();
            }

            // read (user.name) + ('-')
            userNameChar = (userName) + ('-');
            // read ((user.name) + ('-')) + (user.password)
            userNameCharUserPassword = (userNameChar) + (userPassword);
        }
        // batch finished
        if ((dirtyFlags & 0xbL) != 0) {
            // api target 1
            androidx.databinding.adapters.TextViewBindingAdapter.setText(this.name, userName);
        }
        if ((dirtyFlags & 0x8L) != 0) {
            // api target 1
            androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.name, (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged) null, (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged) null, (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged) null, nameandroidTextAttrChanged);
        }
        if ((dirtyFlags & 0xfL) != 0) {
            // api target 1
            androidx.databinding.adapters.TextViewBindingAdapter.setText(this.text, userNameCharUserPassword);
        }
    }

    // Listener Stub Implementations
    // callback impls
    // dirty flag
    private long mDirtyFlags = 0xffffffffffffffffL;
    /* flag mapping
        flag 0 (0x1L): user
        flag 1 (0x2L): user.name
        flag 2 (0x3L): user.password
        flag 3 (0x4L): null
    flag mapping end*/
    //end
}

二、DataBinding Apt/Kapt后产物

2.1、DataBinderMapper

DataBindingUtil类在被加载时(在 Activity.onCreate 中调用),根据成员变量的生命周期,会先初始这个 mapper。

public class DataBindingUtil {
    private static DataBinderMapper sMapper = new DataBinderMapperImpl();
    private static DataBindingComponent sDefaultComponent = null;
}

该 mapper 也是在 apt/kapt 编译阶段生成的:

build/generated/source/kapt/<环境>/androidx/databinding/DataBinderMapperImpl.java

2.1.1、DataBinderMapperImpl

package androidx.databinding;

public class DataBinderMapperImpl extends MergedDataBinderMapper {
  DataBinderMapperImpl() {
    // 调用父类 MergedDataBinderMapper.addMapper 方法
    addMapper(new com.demo.study.DataBinderMapperImpl());
  }
}

2.1.2、MergedDataBinderMapper.addMapper

public class MergedDataBinderMapper extends DataBinderMapper {
    private Set<Class<? extends DataBinderMapper>> mExistingMappers = new HashSet<>();
    private List<DataBinderMapper> mMappers = new CopyOnWriteArrayList<>();
    
    public void addMapper(DataBinderMapper mapper) {
        Class<? extends DataBinderMapper> mapperClass = mapper.getClass();
        
        // 如果不存在,先加入 mExistingMappers
        if (mExistingMappers.add(mapperClass)) {
            // 再加入 mMappers
            mMappers.add(mapper);
            
            // 获取该 mapper 所依赖的其它 DataBinderMapper
            // mapper = com.demo.study.DataBinderMapperImpl
            // 该 mapper 中实现了 collectDependencies 方法
            final List<DataBinderMapper> dependencies = mapper.collectDependencies();
            for(DataBinderMapper dependency : dependencies) {
                addMapper(dependency);
            }
        }
    }
}

2.1.3、DataBinderMapperImpl

该类同样也是自动生成:

build/generated/source/kapt/<环境>/<包名>/databinding/DataBinderMapperImpl.java


public class DataBinderMapperImpl extends DataBinderMapper {
    @Override
    public List<DataBinderMapper> collectDependencies() {
      ArrayList<DataBinderMapper> result = new ArrayList<DataBinderMapper>(1);
      result.add(new androidx.databinding.library.baseAdapters.DataBinderMapperImpl());
      return result;
    }
}

返回的类来自于『databinding-adapters』包。

2.2、res/layout编译后的产物

2.2.1、原始布局(activity_main.xml 为例)

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable name="user" type="com.demo.study.model.User" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.name + '-' + user.password}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <EditText
            android:id="@+id/name"
            android:inputType="text"
            android:importantForAutofill="no"
            android:text="@={user.name}"
            android:hint="输入手机号"
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toBottomOf="@id/text"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"/>

        <EditText
            android:id="@+id/pswd"
            android:inputType="text"
            android:importantForAutofill="no"
            android:text="@={user.password}"
            android:hint="输入密码"
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toBottomOf="@id/name"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"/>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

该 layout 中:

  • data 属性标签,引入具体的 model 类,并指定其名称
  • 有三个控件:
    • 1个 TextView,单向绑定来显示 model 中的数据;
    • 2个 EditText,分别双向绑定 model 中的 name 和 password 字段;

2.2.2、编译后的产物

编译后有会有两个 xml 文件

2.2.2.1、中间产物 activity_main-layout.xml
image.png

注意该中间产物的信息:

  • Variables 是 import 的 Model,可以是多个;
  • Targets 是 Model 绑定到 View 上的信息:
    • 每个根视图,会添加 tag,规则为: layout/activity_xx_数字 (根据在 AndroidManifest.xml 中注册的顺序,从0开始);
    • 但凡 view 与 model 有绑定,就会为其添加 tag,规则会:binding_数字(根据布局中从上到下的顺序,从1开始);
    • 但凡有绑定的view控件,都会有 Expressions 表达式,其中最主要的就是 TwoWay 这个标签,告诉 DataBinding 是单向还是双向绑定;
2.2.2.2、运行时 activity_main.xml
image1.png

该文件为我们实际运行时的真正的布局文件,去掉了最外层 layout 标签,以及 variables 标签,还原成和我们没有用 DataBinding 时的布局一样,只不过,添加了 tag 属性,去掉了显示数据的属性(如:文件控件 text 属性)。

2.3、Activity布局生成的ViewBinding的抽象类和实现类

每个 Activity 都会有一个对应的 layout.xml,APT 后,会根据 2.2.2 中的产物,生成继承于 ViewDataBinding 的类:

  1. 抽象类(ActivityXXXBinding extends ViewDataBinding):view & mode 的实例
build/generated/data_binding_base_class_source_out/<环境>/dataBindingGenBaseClassesDebug/out/<包名>/databinding/......
  1. 实现类(ActivityXXXBindingImpl extends ActivityXXXBinding):该Activity绑定监听 & 执行刷新
build/generated/source/kapt/<环境>/<包名>/databinding/......

三、DataBinding 启动 & 异步渲染流程

Activity.onCreate 调用 DataBindingUtil.setContentView 直到完成,做了哪些事?
正式分析之前,先上一张真机的『Layout Inspector』(在 Tools 菜单中)图

image2.png

DecorView包含的子孙Views(DecorView的父View是PhoneWindow,它是 Window 的唯一子类,再往上就是 Activity 了):

  • LinearLayout
    • R.id.decor_content_parent
    • R.id.content (真正的内容ViewGroup)
    • R.id.action_bar_container (标题栏)
  • R.id.statusBarBackground (状态栏)

3.1、DataBindingUtil.setContentView

public class DataBindingUtil {
    public static <T extends ViewDataBinding> T setContentView(@NonNull Activity activity, int layoutId) {
        return setContentView(activity, layoutId, sDefaultComponent);
    }   
    
    public static <T extends ViewDataBinding> T setContentView(@NonNull Activity activity,
            int layoutId, @Nullable DataBindingComponent bindingComponent) {
        activity.setContentView(layoutId);
        // Activity -> PhoneWindow -> DecorView
        View decorView = activity.getWindow().getDecorView();
        // 查找 R.id.content ViewGroup
        ViewGroup contentView = (ViewGroup) decorView.findViewById(android.R.id.content);
        return bindToAddedViews(bindingComponent, contentView, 0, layoutId);
    }
}

3.2、DataBindingUtil.bindToAddedViews

public class DataBindingUtil {
    private static <T extends ViewDataBinding> T bindToAddedViews(
            DataBindingComponent component, 
            ViewGroup parent, // contentView,肯定只有一个 child 且是 ViewGroup 
            int startChildren, int layoutId // layoutId = R.layout.xxxx,我们项目中的 layout xml
    ) {
        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);
        }
    }
}

3.3、DataBindingUtil.bind

public class DataBindingUtil {
    static <T extends ViewDataBinding> T bind(DataBindingComponent bindingComponent, View root, int layoutId) {
        // 通过 DataBinderMapper 来查找具体的 XxxViewBinding
        // sMapper 中有两个 mapper:
        // [0]: 是 DataBinding APT 为我们生成的 DataBinderMapperImpl
        // [1]: 是 DataBinding Lib 中 baseAdapters 下的 DataBinderMapperImpl
        return (T) sMapper.getDataBinder(bindingComponent, root, layoutId);
    }
}

3.4、MergedDataBinderMapper.getDataBinder

public class MergedDataBinderMapper extends DataBinderMapper {
    @Override
    public ViewDataBinding getDataBinder(DataBindingComponent bindingComponent, View view,int layoutId) {
        // 遍历 mapper
        for(DataBinderMapper mapper : mMappers) {
            ViewDataBinding result = mapper.getDataBinder(bindingComponent, view, layoutId);
            if (result != null) {
                return result;
            }
        }
        if (loadFeatures()) {
            return getDataBinder(bindingComponent, view, layoutId);
        }
        return null;
    }
}

3.5、<包名>.DataBinderMapperImpl.getDataBinder

// 自动生成的
package com.demo.study;

public class DataBinderMapperImpl extends DataBinderMapper {
  private static final int LAYOUT_ACTIVITYMAIN = 1;
  private static final int LAYOUT_ACTIVITYSECOND = 2;
  private static final SparseIntArray INTERNAL_LAYOUT_ID_LOOKUP = new SparseIntArray(2);

  static {
    INTERNAL_LAYOUT_ID_LOOKUP.put(com.demo.study.R.layout.activity_main, LAYOUT_ACTIVITYMAIN);
    INTERNAL_LAYOUT_ID_LOOKUP.put(com.demo.study.R.layout.activity_second, LAYOUT_ACTIVITYSECOND);
  }

  @Override
  public ViewDataBinding getDataBinder(DataBindingComponent component, View view, int layoutId) {
    // 根据 layoutId 来查找 LAYOUT_ACTIVITYXXXXX
    int localizedLayoutId = INTERNAL_LAYOUT_ID_LOOKUP.get(layoutId);
    
    if(localizedLayoutId > 0) {
      // 获取根视图的 tag: layout/activity_xxx_数字(如:layout/activity_main_0)
      final Object tag = view.getTag();
      if(tag == null) {
        throw new RuntimeException("view must have a tag");
      }
      
      // 根据 tag 找到对应的 ViewBinding 实现类
      switch(localizedLayoutId) {
        case  LAYOUT_ACTIVITYMAIN: {
          if ("layout/activity_main_0".equals(tag)) {
            return new ActivityMainBindingImpl(component, view);
          }
          throw new IllegalArgumentException("The tag for activity_main is invalid. Received: " + tag);
        }
        case  LAYOUT_ACTIVITYSECOND: {
          if ("layout/activity_second_0".equals(tag)) {
            return new ActivitySecondBindingImpl(component, view);
          }
          throw new IllegalArgumentException("The tag for activity_second is invalid. Received: " + tag);
        }
      }
    }
    return null;
  }
}

3.6、AcvitityXXXBindingImpl(公有构造函数)

public class ActivityMainBindingImpl extends ActivityMainBinding {
    public ActivityMainBindingImpl(@Nullable androidx.databinding.DataBindingComponent bindingComponent, @NonNull View root) {
        // 重点看 mapBindings 方法
        // root = 根视图( tag = layout/activity_main_0 )
        // 为啥是写死是 4 ?这个就是中间产物 activity_main-layout.xml 中的 Targets 个数
        this(bindingComponent, root, mapBindings(bindingComponent, root, 4, sIncludes, sViewsWithIds));
    }
}

3.7、ViewDataBinding.mapBindings

public abstract class ViewDataBinding extends BaseObservable {
    protected static Object[] mapBindings(DataBindingComponent bindingComponent, View root, int numBindings, 
            ViewDataBinding.IncludedLayouts includes, SparseIntArray viewsWithIds) {
        // 创建 numBindings 个数的绑定对象数组
        Object[] bindings = new Object[numBindings];
        // 从我们的根视图开始,递归遍历找出所有含有 binding_数字 的控件,赋值到 bindings 中
        mapBindings(bindingComponent, root, bindings, includes, viewsWithIds, true);
        return bindings;
    }
    
    private static void mapBindings(DataBindingComponent bindingComponent, View view,
            Object[] bindings, IncludedLayouts includes, SparseIntArray viewsWithIds,
            boolean isRoot) {
        final int indexInIncludes;
        final ViewDataBinding existingBinding = getBinding(view);
        if (existingBinding != null) {
            return;
        }
        Object objTag = view.getTag();
        final String tag = (objTag instanceof String) ? (String) objTag : null;
        boolean isBound = false;
        if (isRoot && tag != null && tag.startsWith("layout")) {
            // 判断是否是根布局,且 tag 以 layout 开头
            // 根布局的 tag = layout/activity_xxx_数字
            ......
        } else if (tag != null && tag.startsWith(BINDING_TAG_PREFIX)) {
            // 判断 tag 是否以 binding_ 开头
            // 绑定的控件的 tag = binding_数字
            ......
        } else {
            // Not a bound view
            indexInIncludes = -1;
        }
        ......
    
        if (view instanceof  ViewGroup) {
            final ViewGroup viewGroup = (ViewGroup) view;
            final int count = viewGroup.getChildCount();
            for (int i = 0; i < count; i++) {
                // 遍历 ViewGroup 的 children
                .......
                
                if (!isInclude) {
                    // 递归遍历子孙
                    mapBindings(bindingComponent, child, bindings, includes, viewsWithIds, false);
                }
            }
        }
    }
}

3.8、AcvitityXXXBindingImpl(私有构造函数)

public class ActivityMainBindingImpl extends ActivityMainBinding {
    private ActivityMainBindingImpl(androidx.databinding.DataBindingComponent bindingComponent, View root, Object[] bindings) {
        super(bindingComponent, root, 1
            , (android.widget.EditText) bindings[2]
            , (android.widget.EditText) bindings[3]
            , (android.widget.TextView) bindings[1]
            );
         // 将4个binding控件 tag 置 null
         this.mboundView0 = (androidx.constraintlayout.widget.ConstraintLayout) bindings[0];
        this.mboundView0.setTag(null);
        this.name.setTag(null);
        this.pswd.setTag(null);
        this.text.setTag(null);
        // 设置根布局
        setRootTag(root);
        // listeners
        invalidateAll();
    }
    
    @Override
    public void invalidateAll() {
        synchronized(this) {
                mDirtyFlags = 0x8L;
        }
        requestRebind();
    }
}

3.9、ViewDataBinding.requestRebind

public abstract class ViewDataBinding extends BaseObservable {
    protected void requestRebind() {
        if (mContainingBinding != null) {
            mContainingBinding.requestRebind();
        } else {
            // LifecycleOwner
            ......
            
            synchronized (this) {
                if (mPendingRebind) {
                    return;
                }
                mPendingRebind = true;
            }
            
            // 重点哈:详见 3.10
            // 如果设备系统 SDK 版本高于 API-16,即 SDK 4.1+,就用 mChoreographer 来渲染
            if (USE_CHOREOGRAPHER) {
                // mChoreographer 可以用来监控 fps 
                mChoreographer.postFrameCallback(mFrameCallback);
            } else {
                // 使用 UI主线程的 Handler 来运行 Runnable
                mUIThreadHandler.post(mRebindRunnable);
            }
            
            // 最终都会执行 mRebindRunnable
        }
    }
}

3.10、ViewDataBinding(构造函数)

在构造函数中,会创建:

  • Choreographer.FrameCallback
  • 绑定至主线程的 Handler
public abstract class ViewDataBinding extends BaseObservable {
        protected ViewDataBinding(DataBindingComponent bindingComponent, View root, int localFieldCount) {
        mBindingComponent = bindingComponent;
        mLocalFieldObservers = new WeakListener[localFieldCount];
        this.mRoot = root;
        if (Looper.myLooper() == null) {
            throw new IllegalStateException("DataBinding must be created in view's UI Thread");
        }
        if (USE_CHOREOGRAPHER) {
            mChoreographer = Choreographer.getInstance();
            mFrameCallback = new Choreographer.FrameCallback() {
                @Override
                public void doFrame(long frameTimeNanos) {
                    mRebindRunnable.run();
                }
            };
        } else {
            mFrameCallback = null;
            mUIThreadHandler = new Handler(Looper.myLooper());
        }
    }
}

3.11、mRebindRunnable

public abstract class ViewDataBinding extends BaseObservable {
    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;
                }
            }
            
            // 最终调用 AcvitityXXXBindingImpl.executePendingBindings
            executePendingBindings();
        }
    };
}

3.12、AcvitityXXXBindingImpl.executePendingBindings

public class ActivityMainBindingImpl extends ActivityMainBinding  {
    @Override
    protected void executeBindings() {
        long dirtyFlags = 0;
        synchronized(this) {
            dirtyFlags = mDirtyFlags;
            mDirtyFlags = 0;
        }
         com.demo.study.model.User user = mUser;
        java.lang.String userNameCharUserPassword = null;
        java.lang.String userPassword = null;
        java.lang.String userName = null;
        java.lang.String userNameChar = null;
    
        if ((dirtyFlags & 0xfL) != 0) {
                if (user != null) {
                    // read user.password
                    userPassword = user.getPassword();
                    // read user.name
                    userName = user.getName();
                }
                userNameCharUserPassword = (userNameChar) + (userPassword);
        }
        // 根据不同标志位(编译时动态决定),刷新 UI 控件
        if ((dirtyFlags & 0xbL) != 0) {
            androidx.databinding.adapters.TextViewBindingAdapter.setText(this.name, userName);
        }
        if ((dirtyFlags & 0x8L) != 0) {
            androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.name, (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, nameandroidTextAttrChanged);
            androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.pswd, (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, pswdandroidTextAttrChanged);
        }
        if ((dirtyFlags & 0xdL) != 0) {
            androidx.databinding.adapters.TextViewBindingAdapter.setText(this.pswd, userPassword);
        }
        if ((dirtyFlags & 0xfL) != 0) {
            androidx.databinding.adapters.TextViewBindingAdapter.setText(this.text, userNameCharUserPassword);
        }
    }
}

至此,我们的 Activity 从启动、获取 Binding 对象、异步渲染就分析完成!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容