Jetpack ---- DataBinding完全解析(四)DataBinding源码分析补充

此篇博客参考 海的鼻涕

setUser

这里面的代码比较简单,主要分析一下updateRegistration方法。第一个入参localFieldId与第二个入参的userName一一对应。

updateRegistration

在这里插入图片描述
ViewDataBinding

protected boolean updateRegistration(int localFieldId, Observable observable) {
    return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER);
}

updateRegistration第三个参数传了CREATE_PROPERTY_LISTENER,我们先看看CREATE_PROPERTY_LISTENER是什么,再分析updateRegistration方法。

ViewDataBinding

/**
  * Method object extracted out to attach a listener to a bound Observable object.
  */
private static final CreateWeakListener CREATE_PROPERTY_LISTENER = new CreateWeakListener() {
    @Override
    public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {
       return new WeakPropertyListener(viewDataBinding, localFieldId).getListener();
    }
};

private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
            implements ObservableReference<Observable> {
    final WeakListener<Observable> mListener;

    public WeakPropertyListener(ViewDataBinding binder, int localFieldId) {
        mListener = new WeakListener<Observable>(binder, localFieldId, this);
    }

    // …… 

    @Override
    public void onPropertyChanged(Observable sender, int propertyId) {
        ViewDataBinding binder = mListener.getBinder();
        if (binder == null) {
            return;
        }
        Observable obj = mListener.getTarget();
        if (obj != sender) {
            return; // notification from the wrong object?
        }
        binder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId);
    }
}

private static class WeakListener<T> extends WeakReference<ViewDataBinding> {
    private final ObservableReference<T> mObservable;
    protected final int mLocalFieldId;
    private T mTarget;

    public WeakListener(ViewDataBinding binder, int localFieldId,
            ObservableReference<T> observable) {
        super(binder, sReferenceQueue);
        mLocalFieldId = localFieldId;
        mObservable = observable;
    }

    // …… 
}

从上面知道CREATE_PROPERTY_LISTENER是一个CreateWeakListener对象,CreateWeakListener.create()能得到WeakPropertyListener,WeakPropertyListener内有变量WeakListener,WeakListener是个弱引用,持有ViewDataBinding以及mTarget(泛型T即VM)。

我们接着上面看看updateRegistration里面的事情:

private boolean updateRegistration(int localFieldId, Object observable,
        CreateWeakListener listenerCreator) {
    if (observable == null) {
        return unregisterFrom(localFieldId);
    }
    WeakListener listener = mLocalFieldObservers[localFieldId];
    if (listener == null) {
        registerTo(localFieldId, observable, listenerCreator);
        return true;
    }
    if (listener.getTarget() == observable) {
        return false;//nothing to do, same object
    }
    unregisterFrom(localFieldId);
    registerTo(localFieldId, observable, listenerCreator);
    return true;
}

registerTo

mLocalFieldObservers维持了从localFieldId到WeakListener的映射。先从mLocalFieldObservers取localFieldId对应的WeakListener,如果为null的话,就调用registerTo进行注册;如果不为空,而且与之前注册过的不一致的话,则重新注册。那registerTo里面如何进行注册?

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;
    }
    listener.setTarget(observable);
}

通过CreateWeakListener.create()得到WeakListener之后,registerTo将WeakListener存储在mLocalFieldObservers中。然后调用WeakListener的setTarget方法:

private static class WeakListener<T> extends WeakReference<ViewDataBinding> {

    private final ObservableReference<T> mObservable;
    // ......

    public WeakListener(ViewDataBinding binder, int localFieldId,
            ObservableReference<T> observable) {
        super(binder, sReferenceQueue);
        mLocalFieldId = localFieldId;
        mObservable = observable;
    }

    public void setTarget(T object) {
        unregister();
        mTarget = object;
        if (mTarget != null) {
            mObservable.addListener(mTarget);
        }
    }
    // ......
}

然后调用mObservable的addListener方法,mObservable就是在构造WeakListener传入的第三个参数。根据下面的代码,WeakPropertyListener在构造函数里构造WeakListener是传入的是this,因此mObservable其实就是WeakPropertyListener。

private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
        implements ObservableReference<Observable> {
    final WeakListener<Observable> mListener;

    public WeakPropertyListener(ViewDataBinding binder, int localFieldId) {
        mListener = new WeakListener<Observable>(binder, localFieldId, this);
    }

    @Override
    public void addListener(Observable target) {
        target.addOnPropertyChangedCallback(this);
    }
    // ......
}

在addListener里,调用Observable的addOnPropertyChangedCallback,参数为this。BaseObservable实现了接口Observable,在addOnPropertyChangedCallback里,将WeakPropertyListener加入到了mCallbacks(PropertyChangeRegistry)里面。

@Override
public void addOnPropertyChangedCallback(OnPropertyChangedCallback callback) {
    synchronized (this) {
        if (mCallbacks == null) {
            mCallbacks = new PropertyChangeRegistry();
        }
    }
    mCallbacks.add(callback);
}

在这里插入图片描述
当调用setUser后WeakPropertyListener中最后会回调onPropertyChanged方法

@Override
public void onPropertyChanged(Observable sender, int propertyId) {
    ViewDataBinding binder = mListener.getBinder();
    if (binder == null) {
        return;
    }
    Observable obj = mListener.getTarget();
    if (obj != sender) {
        return; // notification from the wrong object?
    }
    binder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId);
}

然后调用了ViewDataBinding的handleFieldChange方法,

private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {
    if (mInLiveDataRegisterObserver) {
        // We're in LiveData registration, which always results in a field change
        // that we can ignore. The value will be read immediately after anyway, so
        // there is no need to be dirty.
        return;
    }
    boolean result = onFieldChange(mLocalFieldId, object, fieldId);
    if (result) {
        requestRebind();
    }
}

然后会判断当观察到的对象发生变化时UI是否需要更改,如果需要调用requestRebind(),这个方法上面已经分析过了。

ViewDataBinding

	 /**
      * 当观察到的对象发生变化时调用。 设置适当的脏标志(如果适用)。
      * @param localFieldId此对象所在的mLocalFieldObservers的索引。
      * @param对象已更改的对象。
      * @param fieldId要更改的字段的BR ID;如果未通知特定字段,则返回_all。
      * @return如果此更改应导致UI更改,则为true。
     */
    protected abstract boolean onFieldChange(int localFieldId, Object object, int fieldId);

ActivityMainBindingImpl

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

private boolean onChangeUser(com.wll.android.sourcecodeanalysis.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;
    }
    return false;
}

最后调用到的 ActivityMainBindingImpl.executeBindings 会根据脏标志进行判断执行什么ui操作。

ActivityMainBindingImpl在这里插入图片描述
在这里插入图片描述
这样一来V和VM的联系就通过ViewDatabinding建立起来了。V(Activity)内有ViewDatabinding,而ViewDatabinding里持有各个V(布局中的元素)的引用。ViewDataBinding有VM的变量,而VM内的PropertyChangeRegistry监听实则为WeakPropertyListener,WeakPropertyListener得到的WeakListener能获取到ViewDatabinding的引用。

VM变化如何通知View

前面我们已经讲过了V和VM是如何建立起联系的,接下来我们跟着流程看看具体如何?

我们知道,如果要达到VM变化时自动绑定到View上,有下面俩种方式:

  • 继承自BaseObservable,在getter上增加@Bindable注解,在setter里增加代码notifyPropertyChanged(BR.xxx)。
  • 无需继承,需要将属性替换为Observable类,例如ObservableInt、ObservableField等。

这两种本质上都是一样的。在第二种方式中,当属性发生变化时,会调用notifyChange,而notifyChange与notifyPropertyChanged做的事情都是一样的,都是调用mCallbacks.notifyCallbacks去通知。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
mCallbacks添加监听的过程上面我们已经分析过了,也可以通过函数调用,find usages,一层层往上寻找。BaseObservable.addOnPropertyChangedCallback(BaseObservable) -> ViewDataBinding.WeakPropertyListener.addListener(WeakPropertyListener) -> ViewDataBinding.WeakListener.setTarget(WeakListener)-> ViewDataBinding.registerTo。到这里,就和上面的registerTo方法“会师”了,因此在调用binding.setUser(user)绑定时,就在Observable上加了监听,观察者就是WeakPropertyListener。当VM发生变化时,会通过mCallbacks.notifyCallbacks将变化发送出去。

那当VM发生变化时,notifyCallbacks又是如何将变化发送出去呢?

我们一层层往下跟踪,CallbackRegistry.notifyCallbacks() -> CallbackRegistry.notifyRecurse() -> CallbackRegistry.notifyRemainder(CallbackRegistry) -> CallbackRegistry.notifyFirst64(CallbackRegistry),最后到达下面这个方法:

CallbackRegistry

/**
  * Notify callbacks from startIndex to endIndex, using bits as the bit status
  * for whether they have been removed or not. bits should be from mRemainderRemoved or
  * mFirst64Removed. bits set to 0 indicates that all callbacks from startIndex to
  * endIndex should be notified.
  *
  * @param sender The originator. This is an opaque parameter passed to
  * {@link CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int, Object)}
  * @param arg An opaque parameter passed to
  * {@link CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int, Object)}
  * @param arg2 An opaque parameter passed to
  * {@link CallbackRegistry.NotifierCallback#onNotifyCallback(Object, Object, int, Object)}
  * @param startIndex The index into the mCallbacks to start notifying.
  * @param endIndex One past the last index into mCallbacks to notify.
  * @param bits A bit field indicating which callbacks have been removed and shouldn't
  *             be notified.
  */
private void notifyCallbacks(T sender, int arg, A arg2, final int startIndex,
        final int endIndex, final long bits) {
    long bitMask = 1;
    for (int i = startIndex; i < endIndex; i++) {
        if ((bits & bitMask) == 0) {
            mNotifier.onNotifyCallback(mCallbacks.get(i), sender, arg, arg2);
        }
        bitMask <<= 1;
    }
}

而mNotifier其实就是在BaseObservable构造PropertyChangeRegistry传入的参数。
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
关键代码如下:

public CallbackRegistry(NotifierCallback<C, T, A> notifier) {
    mNotifier = notifier;
}

private static final CallbackRegistry.NotifierCallback<Observable.OnPropertyChangedCallback, Observable, Void> NOTIFIER_CALLBACK = new CallbackRegistry.NotifierCallback<Observable.OnPropertyChangedCallback, Observable, Void>() {
    @Override
    public void onNotifyCallback(Observable.OnPropertyChangedCallback callback, Observable sender,
            int arg, Void notUsed) {
        callback.onPropertyChanged(sender, arg);
    }
};

因此调用mNotifier.onNotifyCallback实际上就是调用mCallbacks.get(i).onPropertyChanged(),我们进一步看看

private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
            implements ObservableReference<Observable> {
    final WeakListener<Observable> mListener;

    // …… 

    @Override
    public void onPropertyChanged(Observable sender, int propertyId) {
        ViewDataBinding binder = mListener.getBinder();
        if (binder == null) {
            return;
        }
        Observable obj = mListener.getTarget();
        if (obj != sender) {
            return; // notification from the wrong object?
        }
        binder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId);
    }
}

可以看到onPropertyChanged调用了编译生成的ActivityMainBinding的onFieldChange方法将mDirtyFlags标识为需要重新绑定VM到V上,并且调用requestRebind方法。requestRebind方法前面已经介绍过,最后能调用到ActivityMainBinding的executeBindings进行界面绑定的工作。这部分上面已经分析过了。

V的变化如何同步到VM

DataBinding在旧版本中是不支持这个功能的,后来才完善了这个功能。例如

<Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@={user.name}" />

在使用双向绑定后,看看生成的ActivityMainBinding有什么变化?可以发现在executeBindings里多了一点代码:

@Override
protected void executeBindings() {
    // …… 
    if ((dirtyFlags & 0x4L) != 0) {
        // api target 1

        android.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.button, (android.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (android.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (android.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, buttonandroidTextAttrChanged);
    }
}

在这个方法里调用了setTextWatcher去监听Button的TextWatcher。

TextViewBindingAdapter

@BindingAdapter(value = {"android:beforeTextChanged", "android:onTextChanged",
        "android:afterTextChanged", "android:textAttrChanged"}, requireAll = false)
public static void setTextWatcher(TextView view, final BeforeTextChanged before,
        final OnTextChanged on, final AfterTextChanged after,
        final InverseBindingListener textAttrChanged) {
    final TextWatcher newValue;
    if (before == null && after == null && on == null && textAttrChanged == null) {
        newValue = null;
    } else {
        newValue = new TextWatcher() {
            // …… 

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
// …...
                if (textAttrChanged != null) {
                    textAttrChanged.onChange();
                }
            }

            // …...
        };
    }
    // …...
    if (newValue != null) {
        view.addTextChangedListener(newValue);
    }
}

当V发生变化时,会调buttonandroidTextAttrChanged的onChange方法。

// Inverse Binding Event Handlers
private android.databinding.InverseBindingListener buttonandroidTextAttrChanged = new android.databinding.InverseBindingListener() {
    @Override
    public void onChange() {
        // Inverse of user.name.get()
        //         is user.name.set((java.lang.String) callbackArg_0)
        java.lang.String callbackArg_0 = android.databinding.adapters.TextViewBindingAdapter.getTextString(button);
        // localize variables for thread safety
        // user.name
        android.databinding.ObservableField<java.lang.String> userName = null;
        // user.name != null
        boolean userNameJavaLangObjectNull = false;
        // user != null
        boolean userJavaLangObjectNull = false;
        // user
        com.example.databindingdemo.User user = mUser;
        // user.name.get()
        java.lang.String userNameGet = null;

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

            userName = user.getName();

            userNameJavaLangObjectNull = (userName) != (null);
            if (userNameJavaLangObjectNull) {
                userName.set(((java.lang.String) (callbackArg_0)));
            }
        }
    }
};

在上面buttonandroidTextAttrChanged的onChange回调里,将变动后的值赋值到VM上。这样,V的变化就自动同步到VM上了。

如何避免findViewById

在介绍双向绑定的原理时,提过“在layout中设置了id属性的,可以直接通过ViewBinding.xxx进行访问”,这种方式避免了findViewById的操作,那本质上是怎么实现的呢?

在初始化时,我们是通过DataBindingUtil.setContentView来建立layout与ViewBinding的联系,因此从这个方法开始分析:

public static <T extends ViewDataBinding> T setContentView(Activity activity, int layoutId) {
     return setContentView(activity, layoutId, sDefaultComponent);
 }

public static <T extends ViewDataBinding> T setContentView(Activity activity, int layoutId,
        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);
}

setContentView直接调用同名方法,而在这个同名方法内,先设置为activity的contentView,然后将contentView传入bindToAddedViews方法。

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);
    }
}

static <T extends ViewDataBinding> T bind(DataBindingComponent bindingComponent, View root,
        int layoutId) {
    return (T) sMapper.getDataBinder(bindingComponent, root, layoutId);
}

获取到layout中的根布局,并且调用bind方法。bind方法内调用DataBinderMapper的getDataBinder方法。DataBinderMapper前面介绍过,也是编译时生成的类,主要是建立layout与ViewBinding之间的映射。

public android.databinding.ViewDataBinding getDataBinder(android.databinding.DataBindingComponent bindingComponent, android.view.View view, int layoutId) {
    switch(layoutId) {
            case com.example.databindingdemo.R.layout.activity_main:
                return com.example.databindingdemo.databinding.ActivityMainBinding.bind(view, bindingComponent);
    }
    return null;
}

这里根据layoutId调用对应ViewBinding的bind方法,ViewBinding的名称是根据layoutId生成的,例如activity_main对应的ViewBinding名称为ActivityMainBinding。

public static ActivityMainBinding bind(android.view.View view, android.databinding.DataBindingComponent bindingComponent) {
    if (!"layout/activity_main_0".equals(view.getTag())) {
        throw new RuntimeException("view tag isn't correct on view:" + view.getTag());
    }
    return new ActivityMainBinding(bindingComponent, view);
}

bind方法里面构造了一个ActivityMainBinding对象。

public ActivityMainBinding(android.databinding.DataBindingComponent bindingComponent, View root) {
    super(bindingComponent, root, 2);
    final Object[] bindings = mapBindings(bindingComponent, root, 2, sIncludes, sViewsWithIds);
    this.button = (android.widget.Button) bindings[1];
    this.button.setTag(null);
    this.mboundView0 = (android.widget.RelativeLayout) bindings[0];
    this.mboundView0.setTag(null);
    setRootTag(root);
    // listeners
    invalidateAll();
}

原作者生成的ActivityMainBindingImpl代码应该是之前版本的代码,3.6.4版本生成的代码如下:
在这里插入图片描述

在构造函数里面,我们看到对button、mboundView0进行了强转赋值操作,因此可以知道mapBindings得到的bindings数组就是View数组。mapBindings方法比较长,我们分成三部分来看看:

从view的tag中获取缓存,防止多次初始化

protected static Object[] mapBindings(DataBindingComponent bindingComponent, View root,
            int numBindings, IncludedLayouts includes, SparseIntArray viewsWithIds) {
        Object[] bindings = new Object[numBindings];
        mapBindings(bindingComponent, root, bindings, includes, viewsWithIds, true);
        return bindings;
    }
private static void mapBindings(DataBindingComponent bindingComponent, View view,
        Object[] bindings, IncludedLayouts includes, SparseIntArray viewsWithIds,
        boolean isRoot) {
    // ……
    final ViewDataBinding existingBinding = getBinding(view);
    if (existingBinding != null) {
        return;
    }
    final String tag = (String) view.getTag();
    // ……
}

	static ViewDataBinding getBinding(View v) {
        if (v != null) {
            return (ViewDataBinding) v.getTag(R.id.dataBinding);
        }
        return null;
    }

将view存储在bindings数组内分为三种情况,与前面生成的ViewBinding内的view变量类型一致,一为根布局,tag以layout开头;二为设置了@{}的,tag以binding开头;三为设置了id属性的

private static void mapBindings(DataBindingComponent bindingComponent, View view,
        Object[] bindings, IncludedLayouts includes, SparseIntArray viewsWithIds,
        boolean isRoot) {
    // ……
    if (isRoot && tag != null && tag.startsWith("layout")) { // tag以layout开头
        final int underscoreIndex = tag.lastIndexOf('_');
        if (underscoreIndex > 0 && isNumeric(tag, underscoreIndex + 1)) {
            final int index = parseTagInt(tag, underscoreIndex + 1);
            if (bindings[index] == null) {
                bindings[index] = view;
            }
            indexInIncludes = includes == null ? -1 : index;
            isBound = true;
        } else {
            indexInIncludes = -1;
        }
    } else if (tag != null && tag.startsWith(BINDING_TAG_PREFIX)) { // tag以binding_开头
        int tagIndex = parseTagInt(tag, BINDING_NUMBER_START);
        if (bindings[tagIndex] == null) {
            bindings[tagIndex] = view;
        }
        isBound = true;
        indexInIncludes = includes == null ? -1 : tagIndex;
    } else {
        // Not a bound view
        indexInIncludes = -1;
    }
    if (!isBound) { // 设置了id的
        final int id = view.getId();
        if (id > 0) {
            int index;
            if (viewsWithIds != null && (index = viewsWithIds.get(id, -1)) >= 0 &&
                     bindings[index] == null) {
                bindings[index] = view;
            }
        }
    }
    // ……
}

这部分判断如果是ViewGroup的话,则判断子View是不是include的,如果是的话,则使用DataBindingUtil.bind进行递归;如果不是include,则直接使用mapBindings进行递归

private static void mapBindings(DataBindingComponent bindingComponent, View view,
        Object[] bindings, IncludedLayouts includes, SparseIntArray viewsWithIds,
        boolean isRoot) {
    // ……
    if (view instanceof  ViewGroup) {
        final ViewGroup viewGroup = (ViewGroup) view;
        final int count = viewGroup.getChildCount();
        int minInclude = 0;
        for (int i = 0; i < count; i++) {
            final View child = viewGroup.getChildAt(i);
            boolean isInclude = false;
            if (indexInIncludes >= 0) { // include的layout,使用DataBindingUtil.bind进行递归
                String childTag = (String) child.getTag();
                if (childTag != null && childTag.endsWith("_0") &&
                        childTag.startsWith("layout") && childTag.indexOf('/') > 0) {
                    // This *could* be an include. Test against the expected includes.
                    int includeIndex = findIncludeIndex(childTag, minInclude,
                            includes, indexInIncludes);
                    if (includeIndex >= 0) {
                        isInclude = true;
                        minInclude = includeIndex + 1;
                        final int index = includes.indexes[indexInIncludes][includeIndex];
                        final int layoutId = includes.layoutIds[indexInIncludes][includeIndex];
                        int lastMatchingIndex = findLastMatching(viewGroup, i);
                        if (lastMatchingIndex == i) {
                            bindings[index] = DataBindingUtil.bind(bindingComponent, child,
                                    layoutId);
                        } else {
                            final int includeCount =  lastMatchingIndex - i + 1;
                            final 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) { // 不是include的layout ,使用mapBindings进行递归
                mapBindings(bindingComponent, child, bindings, includes, viewsWithIds, false);
            }
        }
    }
    // ……
}

通过这三个步骤,递归得到最后的bindings数组。如果设置了id的,就将view变量设置为public,这样就避免了findViewById的代码。这种方式从性能上比findViewById高效,因为databinding只需要遍历一次view数,而findViewById多次调用会遍历多次

ActivityMainBinding.inflate(getLayoutInflater())是如何建立Activity和View的关联的

在这里插入图片描述
ActivityMainBinding

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

  /**
   * This method receives DataBindingComponent instance as type Object instead of
   * type DataBindingComponent to avoid causing too many compilation errors if
   * compilation fails for another reason.
   * https://issuetracker.google.com/issues/116541301
   * @Deprecated Use DataBindingUtil.inflate(inflater, R.layout.activity_main, null, false, component)
   */
  @NonNull
  @Deprecated
  public static ActivityMainBinding inflate(@NonNull LayoutInflater inflater,
      @Nullable Object component) {
    return ViewDataBinding.<ActivityMainBinding>inflateInternal(inflater, R.layout.activity_main, null, false, component);
  }

在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述
这整个流程跟DataBindingUtil.setContentView类似最后都会调用DataBindingUtil.bind。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值