mPreSortedChildren = new ArrayList<>(childrenCount);
} else {
// callers should clear, so clear shouldn’t be necessary, but for safety…
mPreSortedChildren.clear();
mPreSortedChildren.ensureCapacity(childrenCount);
}
final boolean customOrder = isChildrenDrawingOrderEnabled();
for (int i = 0; i < childrenCount; i++) {
// add next child (in child order) to end of list
final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
final View nextChild = mChildren[childIndex];
final float currentZ = nextChild.getZ();
// insert ahead of any Views with greater Z
int insertIndex = i;
while (insertIndex > 0 && mPreSortedChildren.get(insertIndex - 1).getZ() > currentZ) {
insertIndex–;
}
mPreSortedChildren.add(insertIndex, nextChild);
}
return mPreSortedChildren;
}
它里面是通过一个getAndVerifyPreorderedIndex方法来获取对应的子VIew索引,这个方法要传进去一个叫customOrder的boolean。
这个customOrder,看名字可以知道,是自定义顺序的意思,如果它为true的话,接着会通过getChildDrawingOrder(int childCount, int i)方法来获取对应的索引,而且,这个方法是protected的,所以我们可以通过重写这个方法并根据参数"i"来决定返回哪一个View所对应的索引,从而改变分发的顺序。
protected int getChildDrawingOrder(int childCount, int i) {
return i;
}
那这个customOrder,什么时候为true呢?
在buildOrderedChildList方法里可以看到这么一句:
final boolean customOrder = isChildrenDrawingOrderEnabled();
emmmm,也就是说,如果要自定义这个顺序的话,还需要调用setChildrenDrawingOrderEnabled(true)来开启。
重新捋一捋流程:
1. setChildrenDrawingOrderEnabled(true)来开启自定义顺序;
2. 重写getChildDrawingOrder方法来决定什么时候要返回哪个子View;
###2. AppCompatTextView 与 TextView 有什么区别?
1. compat库是如何将TextView替换为AppCompatTextVew的?
2. 为什么要进行替换?
3. 根据替换相关原理,我们可以做哪些事情?
####先从第二问开始吧:
AppCompatTextView继承自TextView,是对TextView的一种扩展,因为在5.0中首次推出了MaterialDesign这种设计风格。
但是众所周知的,5.0推出不可能所有的设备全都一下子更新到最新版本,为了在早期版本上实现新的功能(这些新功能比如从源码注释中解读到比如backgroundTint属性,根据文本内容自适应大小等).
即为了新特性同样可以兼容老版本,framework在创建TextView实例的时候,自动帮我们进行了替换。
其它的AppCompatXXX与XXX的关系也是如此。
####第一问:
然后第一问,如何完成替换的,我们这里只拿最直观的流程举例,且尽可能的简化源码过程,在讨论这个问题之前,先了解几个预备知识:
View是怎么被解析创建出来的:
**1.LayoutInflater:**将布局XML文件实例化为其对应的View对象,我们在Activity中通过setContentView传入一个Layout的资源文件id,最终该方法最终会调用到PhoneWindow的setContentView方法,这个方法里面有调用到
mLayoutInflater.inflate(layoutResID, mContentParent);
2.inflate方法,该方法的作用是将指定的XML文件填充到View的层次结构中去,最终无论通过什么途径调用到inflate方法,都会走到三个参数的重载方法这里:
return inflate(parser, root, attachToRoot);
parser你可以认为持有将Layout.XML解析后的数据。后两个参数的意义如下:
1. root为null,attchToRoot无意义,inflate返回的是当前XML对应的根布局。
2. root不为null且attachToRoot为true,则整个XML对应的布局就设置了根布局是root。
3. root不为null且attachToRoot为false,则会将root的layoutParames设置给当前XML的布局。
知道了LayoutInflate.inflate做了什么,再往下,inflate中会调用createViewFromTag,从方法名就能知道,继续往下走,我们离答案越来越近了。
createViewFromTag做的事情非常有意思:
先看到787行这个if-else,条件是name中有没有"."字符,如果有我们会执行onCreateView,如果没有会执行createView。
####name啥时候有点?
自定义控件的时候。
当是系统控件的时候,createView会有一个填充了第二个参数的调用:
createView(name, “android.view.”, attrs);补上了View控件的全路径名,而自定义控件则不需要,因为传入的name就是一个全路径名。
####为什么要全路径名?
因为View控件对象的创建是通过反射来实现的:
clazz = mContext.getClassLoader().loadClass(
prefix != null ? (prefix + name) : name).asSubclass(View.class);
…
constructor = clazz.getConstructor(mConstructorSignature);
constructor.setAccessible(true);
sConstructorMap.put(name, constructor);
// …
args[1] = attrs;
final View view = constructor.newInstance(args);
下面对这几步做一个总结:
XML中保存了ViewTree的结构和View的相关标签信息(包括View的类型和一些属性值),然后这些信息会在后面通过反射的方式(如果没有Factory2和Factory的话)创建实例对象,如果创建的是ViewGroup,则会对它的子View遍历重复创建步骤,创建完View对象后,会add到对应的ViewGroup中。
其中相关方法的调用流程是:
inflate->rInflate->createViewFromTag->createView。
好像还是没有看到替换?
还是上一张图,我们只解释了后半部分,没有解释前半部分,那么什么是Factory?
继续往下看:
createViewFromTag中会先判断有没有Factory或者Factory2的对象,如果有,则调用Factory的onCreateView方法。
这两个类都是接口,其中Factory2是Factory的子接口,都只有唯一一个onCreateView方法。
不同之处在于Factory2的onCreateView方法传入了parentView。
该方法的作用就是你可以借助它来改造XML中已经存在了的Tag的值。所以Factory2可以达到改造parentView的目的。
但是我们在日常中根本就没有任何地方接触到了Factory(2)呀,那么它是不是就直接是null呢?
到这里又是一番源码调来调去,为了便于理解,只需要知道,这个东西(Factory2),在最开始AppCompatActivity(为了兼容低版本,我们现在Activity默认都是继承自它)中的onCreate方法中就已经通过层层调用被设置好了。
文末不管怎么样,不论是什么样的大小面试,要想不被面试官虐的不要不要的,只有刷爆面试题题做好全面的准备,当然除了这个还需要在平时把自己的基础打扎实,这样不论面试官怎么样一个知识点里往死里凿,你也能应付如流啊~
小编将自己6年以来的面试经验和学习笔记都整理成了一个**937页的PDF,**以及我学习进阶过程中看过的一些优质视频教程。**上传在我的GitHub中:Android架构视频+BATJ面试专题PDF+学习笔记**请君自取,无偿分享!
99%E4%BA%9B%EF%BC%9F%E5%A6%82%E4%BD%95%E9%9D%A2%E8%AF%95%E6%8B%BF%E9%AB%98%E8%96%AA%EF%BC%81.md)**请君自取,无偿分享!
[外链图片转存中…(img-piTUiOWd-1646551254977)]
其实看到身边很多朋友抱怨自己的工资很低,包括笔者也是一样的,其原因是在面试过程中没有给面试官一个很好的答案。所以笔者会持续更新面试过程中遇到的问题,也希望大家和笔者一起进步,一起学习。



