侧边栏壁纸
博主头像
慢行的骑兵博主等级

贪多嚼不烂,欲速则不达

  • 累计撰写 29 篇文章
  • 累计创建 27 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录

Jetpack组件-四-DataBinding

慢行的骑兵
2021-09-13 / 0 评论 / 0 点赞 / 81 阅读 / 5,190 字
  • 本篇笔记主要按照三个方面来讲,单项绑定和双向绑定以及源码分析(使用方面会是略写的方式,源码分析是重点);

一.简介

  • 数据绑定
  • 好处
    • 开发中不需要持有控件的引用
    • 拥有双向绑定的特性
    • 数据与UI同步(设计的初衷,Model层数据发生变化,能激活UI的更新)
  • 项目中可以分担部分UI的简单逻辑

二.单向绑定和双向绑定

2.1.单向绑定

  • 有三种

2.1.1.JavaBean继承BaseObservable

  • 在set方法中添加notifyChanged,在set方法中添加notifyChange(会更新所有的UI,可以通过notifyPropertyChanged(BR.xxx)方式来实现只更新单个属性)的方法
//单向绑定的第一种方法
//弊端:业务改变的时候,javabean需要修改
//JavaBean
public class PersonInfo extends BaseObservable {
    private String userName;
    private String passwd;

    public PersonInfo(String userName, String passwd) {
        this.userName = userName;
        this.passwd = passwd;
    }

    @Bindable
    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
        notifyPropertyChanged(BR.userName);
    }

    @Bindable
    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
        notifyPropertyChanged(BR.passwd);
    }
}
  • 持有ObservableField;
  • 在layout中使用viewmodle(推荐);

2.2.双向绑定

  • 知道了单向绑定,双向绑定很简单,增加=即可;

2.3.其它

三.源码分析一

  • 重点来袭
  • 先补充个技巧:我们在分析源码的时候,源码入口的寻找方法,主要根据以下几点进行寻找
    • 三方SDK本身的逻辑,如Okhttp、Retrofit、Glide、Rxjava
      • 一定要注意,是否Hook了Application、Framework的源码,如:组件化、插件化、热修复;
    • activity或者fragment的生命周期相关的代码,如:Lifecycle、Livedata
    • Apt生成的代码,如:Databinding、Butterknife、Dagger2、Hilt
    • 代码的灵异事件(比如:不符合语法规则或不符合自己想要的逻辑等),需要考虑是否有gradle任务做了字节码插桩;
  • 另外,在看源码的过程中,要掌握正确的分析过程,画时序图(代码的执行)和类图(整体的结构);
  • 源码分析一部分,我们要做的是,探讨为什么使用databinding之后,不需要做findViewbyId;

3.1.布局文件

  • 我们按照databinding的要求写布局和设置布局后,databinding会自动生成对应的java文件和xml文件。我们先分析布局文件。比如:写了一个登录的页面,名称为activity_login。apt会自动生成两个布局文件。

01.apt生成的布局文件

3.2.源码的入口

  • //1.入口
    DataBindingUtil.setContentView(this, initContentView())
    
    //2.setContentView    
    public static <T extends ViewDataBinding> T setContentView(@NonNull Activity activity,int layoutId) {
        return setContentView(activity, layoutId, sDefaultComponent);
    }
    
    //3.setContentView   
    public static <T extends ViewDataBinding> T setContentView(@NonNull Activity activity,
                int layoutId, @Nullable DataBindingComponent bindingComponent) {
    	activity.setContentView(layoutId);
        View decorView = activity.getWindow().getDecorView();
        ViewGroup contentView = (ViewGroup) decorView.findViewById(android.R.id.content);
        return bindToAddedViews(bindingComponent, contentView, 0, layoutId);
    }
    
    //4.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);
        }
    }
    
    //6.1.sMapper是一个成员变量,指向DataBinderMapperImpl,DataBinderMapperImpl是apt自动生成的
    private static DataBinderMapper sMapper = new DataBinderMapperImpl();
    
    //5.bind
    static <T extends ViewDataBinding> T bind(DataBindingComponent bindingComponent, View root,
            int layoutId) {
        //6.2.getDataBinder,在3.3中分析
        return (T) sMapper.getDataBinder(bindingComponent, root, layoutId);
    }
    

3.3.DataBinderMapper

public abstract class DataBinderMapper {
	//6.3.查看实现类DataBinderMapperImpl
    public abstract ViewDataBinding getDataBinder(DataBindingComponent bindingComponent, View view,
            int layoutId);
    public abstract ViewDataBinding getDataBinder(DataBindingComponent bindingComponent,
            View[] view, int layoutId);
    public abstract int getLayoutId(String tag);
    public abstract String convertBrIdToString(int id);
    @NonNull
    public List<DataBinderMapper> collectDependencies() {
        // default implementation for backwards compatibility.
        return Collections.emptyList();
    }
}

//6.4.实现类DataBinderMapperImpl的getDataBinder方法
@Override
public ViewDataBinding getDataBinder(DataBindingComponent component, View view, int layoutId) {
  int localizedLayoutId = INTERNAL_LAYOUT_ID_LOOKUP.get(layoutId);
  if(localizedLayoutId > 0) {
    final Object tag = view.getTag();
    if(tag == null) {
      throw new RuntimeException("view must have a tag");
    }
    switch(localizedLayoutId) {
      case  LAYOUT_ACTIVITYLOGIN: {
        //6.5.如果tag为layout/activity_login_0,就new出ActivityLoginBindingImpl
        if ("layout/activity_login_0".equals(tag)) {
          //7.分析ActivityLoginBindingImpl,在步骤3.4中
          return new ActivityLoginBindingImpl(component, view);
        }
        throw new IllegalArgumentException("The tag for activity_login is invalid. Received: " + tag);
      }
      //...
    }
  }
  return null;
}
  • 此时DataBinderMapperImpl和ActivityLoginBindingImpl两个对象在内存中已经存在了(提示:在研究apt生生成的代码,要知道对应的对象初始化到内存中的时机);

3.4.ActivityLoginBindingImpl

public ActivityLoginBindingImpl(@Nullable androidx.databinding.DataBindingComponent bindingComponent, @NonNull View root) {
    //8.分析mapBindings方法
    this(bindingComponent, root, mapBindings(bindingComponent, root, 6, sIncludes, sViewsWithIds));
}

//ViewDataBinding中的方法,参数3,由布局文件中控件的个数来决定
protected static Object[] mapBindings(DataBindingComponent bindingComponent, View root,
            int numBindings, IncludedLayouts includes, SparseIntArray viewsWithIds) {
    //8.1.创建数组
    Object[] bindings = new Object[numBindings];
    //8.2.将标签解析成对象,在3.5中分析
    mapBindings(bindingComponent, root, bindings, includes, viewsWithIds, true);
    return bindings;
}

3.5.将标签解析成对象

  • 该方法的作用(知道即可,内部细节可以不用关注),将View解析出来放入到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")) {
        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)) {
        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) {
        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;
            }
        }
    }

    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 && child.getTag() instanceof String) {
                String childTag = (String) child.getTag();
                if (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) {
                mapBindings(bindingComponent, child, bindings, includes, viewsWithIds, false);
            }
        }
    }
}
  • 返回到步骤8,继续分析ActivityLoginBindingImpl另一个构造方法
//ActivityLoginBindingImpl另一个构造方法
private ActivityLoginBindingImpl(androidx.databinding.DataBindingComponent bindingComponent, View root, Object[] bindings) {
    super(bindingComponent, root, 2
        , (cn.jack.library_weight.SubmitButton) bindings[5]
        , (cn.jack.library_weight.PasswordEditText) bindings[2]
        , (cn.jack.library_weight.ClearEditText) bindings[1]
        , (androidx.appcompat.widget.LinearLayoutCompat) bindings[4]
        , (android.widget.TextView) bindings[3]
        );
    this.etLoginPassword.setTag(null);
    this.etLoginPhone.setTag(null);
    this.mboundView0 = (androidx.appcompat.widget.LinearLayoutCompat) bindings[0];
    this.mboundView0.setTag(null);
    setRootTag(root);
    // listeners
    invalidateAll();
}
  • 总结:步骤3.1-3.5,其实我们分析的就一点,当我们使用了databinding的后,就可以不需要findViewById了。因为DataBindingUtil.setContentView(this, initContentView())返回的对象ActivityLoginBinding存储了布局中View的引用;
  • 使用databinding的弊端:随着项目越来越大,使用databinding会导致内存消耗越来越大,所以,大型项目是不会使用databinding,mvvm的出现主要是为了中小型项目的快速开发。重量级的大型项目(主流还是mvp,混合开发的话,一些UI使用Flutter,底层使用c和c++)是不会使用mvvm的,既要节省内存,又要有运行的快。

四.源码分析二

  • 这部分我们需要探讨的是,databinding是如何做到,model的改变后,view跟着改变;

  • 源码看一轮之后,不建议按照源码的执行流程去分析了,我们得换个角度,如此,才能更快的把握好主体结构;

  • databinding实际上是使用观察者模式来实现的,底层还是View.settext方案来实现View的更新;既然是观察者模式,我们就需要分清楚被观察者和观察者,同时还需要知道如何建立联系的;

4.1.被观察者

  • 我们在xml中通过variable设置的type对象就是被观察者,如下,personInfo和viewModel都是观察者,我们只分析personInfo;
//activity_login.xml中的部分代码
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
            name="personInfo"
            type="cn.jack.module_login.mvvm.modle.entity.PersonInfo" />
        
        <variable
            name="viewModel"
            type="cn.jack.module_login.mvvm.vm.LoginViewModel" />
    </data>
        
    <!-- 省略 -->
        
</layout>   
  • 被观察者确定好了,我们接着分析观察者

4.2.观察者

  • 观察者有两个:ViewDataBinding(抽象类)和ActivityLoginBindingImpl,之所以认定这两者是观察者是因为javabean发生变化的时候,最终会触发这两者的executeBindings方法,从而实现View的更新;
public class ActivityLoginBindingImpl extends ActivityLoginBinding  {
	//...
    @Override
    public boolean setVariable(int variableId, @Nullable Object variable)  {
        boolean variableSet = true;
        if (BR.personInfo == variableId) {
            setPersonInfo((cn.jack.module_login.mvvm.modle.entity.PersonInfo) variable);
        }
        else if (BR.viewModel == variableId) {
            setViewModel((cn.jack.module_login.mvvm.vm.LoginViewModel) variable);
        }
        else {
            variableSet = false;
        }
            return variableSet;
    }

    public void setPersonInfo(@Nullable cn.jack.module_login.mvvm.modle.entity.PersonInfo PersonInfo) {
        updateRegistration(0, PersonInfo);
        this.mPersonInfo = PersonInfo;
        synchronized(this) {
            mDirtyFlags |= 0x1L;
        }
        notifyPropertyChanged(BR.personInfo);
        super.requestRebind();
    }
    public void setViewModel(@Nullable cn.jack.module_login.mvvm.vm.LoginViewModel ViewModel) {
        this.mViewModel = ViewModel;
    }

    @Override
    protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {
        switch (localFieldId) {
            case 0 :
                return onChangePersonInfo((cn.jack.module_login.mvvm.modle.entity.PersonInfo) object, fieldId);
        }
        return false;
    }
    private boolean onChangePersonInfo(cn.jack.module_login.mvvm.modle.entity.PersonInfo PersonInfo, int fieldId) {
        if (fieldId == BR._all) {
            synchronized(this) {
                    mDirtyFlags |= 0x1L;
            }
            return true;
        }
        //..
        return false;
    }

    @Override
    protected void executeBindings() {
        //...
        // batch finished
        if ((dirtyFlags & 0x19L) != 0) {
            // api target 1
            androidx.databinding.adapters.TextViewBindingAdapter.setText(this.etLoginPassword, personInfoPasswd);
        }
        if ((dirtyFlags & 0x10L) != 0) {
            //...
            androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.etLoginPhone, (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, etLoginPhoneandroidTextAttrChanged);
        }
        if ((dirtyFlags & 0x15L) != 0) {
  androidx.databinding.adapters.TextViewBindingAdapter.setText(this.etLoginPhone, personInfoUserName);
        }
    }
    //...
}
  • 观察者也清楚了,我们现在只需要弄明白被观察者跟观察者是如何建立关联,并且被观察者发生改变,被观察者是如何通知观察者做出相应,即可明白databiding的核心原理。

4.3.被观察者和观察者建立关联

  • 这个建立关联的函数为setVariable,如下:
public boolean setVariable(int variableId, @Nullable Object variable)  {
    boolean variableSet = true;
    if (BR.personInfo == variableId) {
        setPersonInfo((cn.jack.module_login.mvvm.modle.entity.PersonInfo) variable);
    }
    else if (BR.viewModel == variableId) {
        setViewModel((cn.jack.module_login.mvvm.vm.LoginViewModel) variable);
    }
    else {
        variableSet = false;
    }
        return variableSet;
}
  • 比如,想要让被观察者personInfo和观察者建立关联,就需要调用ActivityLoginBinding.setVariable(BR.personInfo,personInfo)函数(或者调用setPersonInfo函数);
  • 我们就从setVariable开始逐步分析被观察者和观察者之间是如何建立关联的,这里的逻辑会有些绕,因为这里的建立关联跟传统的观察者模式不一样,传统的比较简单,但是这里用了大量的类和接口才正真的建立其关联。所以,这部分的逻辑会有些赋值,不过我们慢慢分析,还是会比较清晰的。我们就以setPersonInfo作为入口。
//ActivityLoginBindingImpl类中 
//1.步骤1
//---> setPersonInfo(PersonInfo)	
//2.步骤2
//---> updateRegistration(0, PersonInfo);
//3.步骤3
//--->ViewDataBinding类的updateRegistration(int localFieldId, Observable observable)
//4.步骤4	得开始贴详细代码了
//--->updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER)
     
//4.1.先看方法的第三个参数的代码
//CREATE_PROPERTY_LISTENER是ViewDataBinding类中静态的成员变量
//是一个匿名内部类的对象,此时create方法还未被调用
private static final CreateWeakListener CREATE_PROPERTY_LISTENER = new CreateWeakListener() {
    @Override
    public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {
        return new WeakPropertyListener(viewDataBinding, localFieldId).getListener();
    }
};

//4.2.updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER)
//localFieldId = 0,observable = personInfo
private boolean updateRegistration(int localFieldId, Object observable,
            CreateWeakListener listenerCreator) {
    //...
    
    //mLocalFieldObservers是ViewDataBinding类的成员变量,是一个WeakListener数组
    //此时,listener为null
    WeakListener listener = mLocalFieldObservers[localFieldId];
    if (listener == null) {
        //5.步骤5
        registerTo(localFieldId, observable, listenerCreator);
        return true;
    }
    if (listener.getTarget() == observable) {		
        return false;
    }
    //略...
}

//5.步骤5
protected void registerTo(int localFieldId, Object observable,
        CreateWeakListener listenerCreator) {
    //...
    WeakListener listener = mLocalFieldObservers[localFieldId];
    //此时还是为null,进入if
    if (listener == null) {		
        //5.给 listener 赋值为 WeakListener对象
        //listenerCreator是4.1中的CREATE_PROPERTY_LISTENER
        //此时,create方法调用了,WeakPropertyListener类被创建
        listener = listenerCreator.create(this, localFieldId);
        mLocalFieldObservers[localFieldId] = listener;
        //...
    }
    //6.步骤6
    listener.setTarget(observable);
}

//6.步骤6
//执行WeakListener类setTarget方法
private static class WeakListener<T> extends WeakReference<ViewDataBinding> {
    //...

    public void setTarget(T object) {
        unregister();
        mTarget = object;
        if (mTarget != null) {
            //通过上面的CREATE_PROPERTY_LISTENER我们可以知道 
            //mObservable = WeakPropertyListener
            //mTarget = personInfo
            //mObservable在这里是ObservableReference接口,故分析其具体实现类的方法
            //7.步骤7:分析WeakPropertyListener的addListener
            mObservable.addListener(mTarget);
        }
    }

    //...
}

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

    //...

    @Override
    public void addListener(Observable target) {
    	//target = personInfo
    	//调用父类Observable的方法
    	//8.步骤8 	
        target.addOnPropertyChangedCallback(this);
    }

    //...
}


//8.步骤8
public class BaseObservable implements Observable {
	//...
	
    @Override
    public void addOnPropertyChangedCallback(@NonNull OnPropertyChangedCallback callback) {
        synchronized (this) {
            if (mCallbacks == null) {
                mCallbacks = new PropertyChangeRegistry();
            }
        }
        //调用了mCallbacks(PropertyChangeRegistry)中的add方法。最终是将OnPropertyChangedCallback添加到一个List集合中(实际上是该接口的实现类)(需要追踪PropertyChangeRegistry父类的add方法)
        //9.步骤9
        mCallbacks.add(callback);
    }
	
	//...
}
//9.步骤9
//CallbackRegistry类
private List<C> mCallbacks = new ArrayList<C>();
public synchronized void add(C callback) {
    if (callback == null) {
        throw new IllegalArgumentException("callback cannot be null");
    }
    int index = mCallbacks.lastIndexOf(callback);
    if (index < 0 || isRemoved(index)) {
        mCallbacks.add(callback);
    }
}
  • 总结一下,步骤1-步骤9所作的事情,观察者ViewDataBinding中有个数组,每一个被观察者对应该数组中一个WeakListener类,WeakListener给被观察者做了一件事情,给被添加了一个接口,该接口最终是被存储到CallbackRegistry类的集合中;
  • 建立关系到这里已经完成,但是我们还看不出是如何触发,触发时机上跟传统的观察者模式一样,触发的api是定义在了被观察者中。下面,我们来分析通知观察者的api。

4.4.BaseObservable类

  • 通知观察者的api为BaseObservable的notifyPropertyChanged(fieldId)
  • 调用PersonInfo的setUserName,会触发notifyPropertyChanged(BR.userName)(其它也类似,即Model发生变化);
  • 具体一些条件判断等主体框架清楚了之后,有兴趣可以自行研究,细节上的一些判断就不添加;
//10.步骤10
public void notifyPropertyChanged(int fieldId) {
    synchronized (this) {
        if (mCallbacks == null) {
            return;
        }
    }
    //11.步骤11
    mCallbacks.notifyCallbacks(this, fieldId, null);
}

//11.步骤11
public synchronized void notifyCallbacks(T sender, int arg, A arg2) {
    mNotificationLevel++;
    //12.步骤12
    notifyRecurse(sender, arg, arg2);
    mNotificationLevel--;
    if (mNotificationLevel == 0) {
        if (mRemainderRemoved != null) {
            for (int i = mRemainderRemoved.length - 1; i >= 0; i--) {
                final long removedBits = mRemainderRemoved[i];
                if (removedBits != 0) {
                    removeRemovedCallbacks((i + 1) * Long.SIZE, removedBits);
                    mRemainderRemoved[i] = 0;
                }
            }
        }
        if (mFirst64Removed != 0) {
            removeRemovedCallbacks(0, mFirst64Removed);
            mFirst64Removed = 0;
        }
    }
}

//12.步骤12
private void notifyRecurse(T sender, int arg, A arg2) {
    final int callbackCount = mCallbacks.size();
    final int remainderIndex = mRemainderRemoved == null ? -1 : mRemainderRemoved.length - 1;

    // Now we've got all callbakcs that have no mRemainderRemoved value, so notify the
    // others.
    //13.步骤13
    notifyRemainder(sender, arg, arg2, remainderIndex);

    // notifyRemainder notifies all at maxIndex, so we'd normally start at maxIndex + 1
    // However, we must also keep track of those in mFirst64Removed, so we add 2 instead:
    final int startCallbackIndex = (remainderIndex + 2) * Long.SIZE;

    // The remaining have no bit set
    notifyCallbacks(sender, arg, arg2, startCallbackIndex, callbackCount, 0);
}

//13.步骤13
private void notifyRemainder(T sender, int arg, A arg2, int remainderIndex) {
    if (remainderIndex < 0) {		
        //14.步骤14
        notifyFirst64(sender, arg, arg2);
    } else {
        final long bits = mRemainderRemoved[remainderIndex];
        final int startIndex = (remainderIndex + 1) * Long.SIZE;
        final int endIndex = Math.min(mCallbacks.size(), startIndex + Long.SIZE);
        notifyRemainder(sender, arg, arg2, remainderIndex - 1);
        notifyCallbacks(sender, arg, arg2, startIndex, endIndex, bits);
    }
}

//14.步骤14
private void notifyFirst64(T sender, int arg, A arg2) {
    final int maxNotified = Math.min(Long.SIZE, mCallbacks.size());
    //15.步骤15
    notifyCallbacks(sender, arg, arg2, 0, maxNotified, mFirst64Removed);
}

//15.步骤15
private void notifyCallbacks(T sender, int arg, A arg2, final int startIndex,
    private void notifyFirst64(T sender, int arg, A arg2) {
    final int maxNotified = Math.min(Long.SIZE, mCallbacks.size());
    notifyCallbacks(sender, arg, arg2, 0, maxNotified, mFirst64Removed);
}    final int endIndex, final long bits) {
    long bitMask = 1;
    for (int i = startIndex; i < endIndex; i++) {
        if ((bits & bitMask) == 0) {
            //调用CallbackRegistry类的NotifierCallback的实现类的onNotifyCallback
            //16.步骤16
            mNotifier.onNotifyCallback(mCallbacks.get(i), sender, arg, arg2);
        }
        bitMask <<= 1;
    }
}

//16.步骤16    
public abstract static class NotifierCallback<C, T, A> {
    public abstract void onNotifyCallback(C callback, T sender, int arg, A arg2);
}

public class PropertyChangeRegistry extends CallbackRegistry<OnPropertyChangedCallback, Observable, Void> {
    private static final NotifierCallback<OnPropertyChangedCallback, Observable, Void> NOTIFIER_CALLBACK = new NotifierCallback<OnPropertyChangedCallback, Observable, Void>() {
        public void onNotifyCallback(OnPropertyChangedCallback callback, Observable sender, int arg, Void notUsed) {
            //实际调用的位置	 
            //调用Observable类中的OnPropertyChangedCallback的实现类的onPropertyChanged方法
            //17.步骤17 
            callback.onPropertyChanged(sender, arg);
        }
    };

    public PropertyChangeRegistry() {
        super(NOTIFIER_CALLBACK);
    }

    public void notifyChange(@NonNull Observable observable, int propertyId) {
        this.notifyCallbacks(observable, propertyId, (Object)null);
    }
}

//17.步骤17
abstract class OnPropertyChangedCallback {
    public abstract void onPropertyChanged(Observable sender, int propertyId);
}

private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
        implements ObservableReference<Observable> {
    //...

	//实际调用
	//17.步骤17
    @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?
        }
        //调用handleFieldChange   
        //18.步骤18
        binder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId);
    }
}
  • 现在可以把步骤1-步骤18联系起来,也就是被观察者和观察者建立了关联,同时model改变后,被观察者发送通知给观察者,最终是回调了ViewDataBinding的handleFieldChange方法,我们只要分析出该方法最终的调用,看具体的操作即可;

4.5.ViewDataBinding的handleFieldChange方法

//19.步骤19
private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {
    //...
    //onFieldChange的具体实现在ActivityLoginBindingImpl中
    //内部计算是&和|,有兴趣自行研究一下,被观察者未发生变化,则不会进入if(即属性不需要更新)
    boolean result = onFieldChange(mLocalFieldId, object, fieldId);
    if (result) {		
    	//分析requestRebind
        //20.步骤20
        requestRebind();
    }
}

//20.步骤20
//条件判断略掉(避免过于深入细节)
protected void requestRebind() {
    if (mContainingBinding != null) {
        mContainingBinding.requestRebind();
    } else {
        final LifecycleOwner owner = this.mLifecycleOwner;
        if (owner != null) {
            Lifecycle.State state = owner.getLifecycle().getCurrentState();
            if (!state.isAtLeast(Lifecycle.State.STARTED)) {
                return; // wait until lifecycle owner is started
            }
        }
        synchronized (this) {
            if (mPendingRebind) {
                return;
            }
            mPendingRebind = true;
        }
        if (USE_CHOREOGRAPHER) {
            mChoreographer.postFrameCallback(mFrameCallback);
        } else {
        	//会回调mRebindRunnable的run方法	
            //21.步骤21
            mUIThreadHandler.post(mRebindRunnable);
        }
    }
}

//21.步骤21
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;
            }
        }
        //会调用executePendingBindings
        //22.步骤22
        executePendingBindings();
    }
};

//22.步骤22
public void executePendingBindings() {
    if (mContainingBinding == null) {
        //会调用executeBindingsInternal	
        //23.步骤23
        executeBindingsInternal();
    } else {
        mContainingBinding.executePendingBindings();
    }
}

//23.步骤23
private void executeBindingsInternal() {
    //...
    if (!mRebindHalted) {	
        //抽象方法,具体实现在在ActivityLoginBindingImpl中查看
        //24.步骤24
        executeBindings();		
        //...
    }
    //...
}

//24.步骤24
//ActivityLoginBindingImpl类
protected void executeBindings() {
    long dirtyFlags = 0;
    synchronized(this) {
        dirtyFlags = mDirtyFlags;
        mDirtyFlags = 0;
    }
    java.lang.String personInfoPasswd = null;
    cn.jack.module_login.mvvm.modle.PersonInfo personInfo = mPersonInfo;
    java.lang.String personInfoUserName = null;

    if ((dirtyFlags & 0x1dL) != 0) {
        if ((dirtyFlags & 0x19L) != 0) {
                if (personInfo != null) {
                    // read personInfo.passwd
                    personInfoPasswd = personInfo.getPasswd();
                }
        }
        if ((dirtyFlags & 0x15L) != 0) {
                if (personInfo != null) {
                    // read personInfo.userName
                    personInfoUserName = personInfo.getUserName();
                }
        }
    }
    // batch finished
    if ((dirtyFlags & 0x19L) != 0) {
        // api target 1
 androidx.databinding.adapters.TextViewBindingAdapter.setText(this.etLoginPassword, personInfoPasswd);
    }
    if ((dirtyFlags & 0x10L) != 0) {
        // api target 1
androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.etLoginPassword, (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, etLoginPasswordandroidTextAttrChanged);
        androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.etLoginPhone, (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, etLoginPhoneandroidTextAttrChanged);
    }
    if ((dirtyFlags & 0x15L) != 0) {
        // api target 1

        androidx.databinding.adapters.TextViewBindingAdapter.setText(this.etLoginPhone, personInfoUserName);
    }
}

//TextViewBindingAdapter.setText最终还是View.setText
  • 到这里,databinding的核心原理分析完毕。

4.6.总结

  • 为了避免看源码引起不适,重新把被观察者数据发生改变后是如何通知观察者的做个整理,如下:
被观察者持有CallbackRegistry类的引用,在被观察者数据发生变化的时候,通过调用
CallbackRegistry的方法
--->PropertyChangeRegistry(CallbackRegistry的实现类)的方法
--->OnPropertyChangedCallback的onPropertyChanged方法
--->WeakPropertyListener(OnPropertyChangedCallback的实现类)的onPropertyChanged(WeakPropertyListener是ViewDataBinding的静态内部类)
--->ViewDataBinding类的handleFieldChange方法
--->ViewDataBinding类的requestRebind方法
--->ViewDataBinding类的mRebindRunnable的run方法
--->ViewDataBinding类的executePendingBindings方法
--->ViewDataBinding类executeBindingsInternal方法
--->ViewDataBinding类executeBindings抽象方法(需要找实现类)
--->ActivityLoginBindingImpl类executeBindings方法

4.7.补充两个细节

  • mDirtyFlags与BR之间的计算,是通过&和|来计算的,BR中的变量对应的值在计算中是2的n次方
public class BR {
  public static int _all = 0;

  public static int data = 1;

  public static int passwd = 2;

  public static int personInfo = 3;

  public static int userName = 4;

  public static int viewModel = 5;
}

//ActivityLoginBindingImpl类
//mDirtyFlags存储的信息来判断哪个变量修改了
private boolean onChangePersonInfo(cn.jack.module_login.mvvm.modle.PersonInfo PersonInfo, int fieldId) {
    if (fieldId == BR._all) {
        synchronized(this) {
                mDirtyFlags |= 0x1L;	//2^0		BR._all = 0
        }
        return true;
    }
    else if (fieldId == BR.userName) {
        synchronized(this) {
                mDirtyFlags |= 0x4L;	//2^1		BR.userName = 1	
        }
        return true;
    }
    else if (fieldId == BR.passwd) {
        synchronized(this) {
                mDirtyFlags |= 0x8L;	//2^2		BR.passwd = 2	
        }
        return true;
    }
    return false;
}
  • 初始的数据是如何获取的,ViewDataBinding的静态代码块初始化的位置,有设置回调。当View绑定到窗口的时候 onViewAttachedToWindow 自动触发该回调(framework层调用),从而执行了mRebindRunnable的run方法,最终也是调用ActivityLoginBindingImpl类executeBindings方法;
0

评论区