美文网首页安卓面试
DataBinding源码分析

DataBinding源码分析

作者: 青叶小小 | 来源:发表于2020-12-30 00:28 被阅读0次

    一、前言

    在编译阶段,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 对象、异步渲染就分析完成!

    相关文章

      网友评论

        本文标题:DataBinding源码分析

        本文链接:https://www.haomeiwen.com/subject/iqcqoktx.html