目录
测量过程
https://www.jianshu.com/p/87bc61b8a195
https://blog.csdn.net/dnntjc/article/details/82055393
onMeausre方法解析(API28)
第一步:排序
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mDirtyHierarchy) {
mDirtyHierarchy = false;
sortChildren();
}
...
@Override
public void requestLayout() {
super.requestLayout();
mDirtyHierarchy = true;
}
通过复写打日志发现requestLayout先于onMeasure执行,所以 mDirtyHierarchy是true,sortChildren方法会执行。
搞清楚排序,首先得搞清楚RelativeLayout内部的数据结构的架构。
Pools
https://blog.csdn.net/go_going/article/details/81587289
为了避免重复的创建对象,大致思想是:Pool的acquire()方法会取缓存池的最后一个对象返回并将缓存池这个位置的元素置为null,release()方法会将对象放到缓存池。这样只要缓存池有对象,就不用再new对象了。
这也是内存优化一种手段,面试可以说说。
拓扑排序
- 有向图出度与入度的概念
https://blog.csdn.net/qq_43824791/article/details/88792899
入度就是:有向图的某个顶点作为终点的次数和。
出度就是:有向图的某个顶点作为起点的次数和。
https://blog.csdn.net/qq_41713256/article/details/80805338 (拓扑排序入门)https://www.jianshu.com/p/243da3f85032 (结合RelativeLayout的源码说明拓扑排序的应用)
排序方法
private void sortChildren() {
final int count = getChildCount();
if (mSortedVerticalChildren == null || mSortedVerticalChildren.length != count) {
mSortedVerticalChildren = new View[count];
}
if (mSortedHorizontalChildren == null || mSortedHorizontalChildren.length != count) {
mSortedHorizontalChildren = new View[count];
}
//将子View装入一个依赖图中
final DependencyGraph graph = mGraph;
graph.clear();
for (int i = 0; i < count; i++) {
graph.add(getChildAt(i));
}
//获取竖向规则相关的View
graph.getSortedViews(mSortedVerticalChildren, RULES_VERTICAL);
//获取水平规则相关的View
graph.getSortedViews(mSortedHorizontalChildren, RULES_HORIZONTAL);
}
...
/**
* Adds a view to the graph.
*
* @param view The view to be added as a node to the graph.
*/
void add(View view) {
final int id = view.getId();
final Node node = Node.acquire(view);
if (id != View.NO_ID) {
mKeyNodes.put(id, node);
}
mNodes.add(node);
}
- #### 看看 graph.getSortedViews的实现
越是先被依赖的View,越在数组的前面。
/**
* Builds a sorted list of views. The sorting order depends on the dependencies
* between the view. For instance, if view C needs view A to be processed first
* and view A needs view B to be processed first, the dependency graph
* is: B -> A -> C. The sorted array will contain views B, A and C in this order.
*
* @param sorted The sorted list of views. The length of this array must
* be equal to getChildCount().
* @param rules The list of rules to take into account.
*/
void getSortedViews(View[] sorted, int... rules) {
final ArrayDeque<Node> roots = findRoots(rules);
int index = 0;
Node node;
while ((node = roots.pollLast()) != null) {
final View view = node.view;
final int key = view.getId();
sorted[index++] = view;
final ArrayMap<Node, DependencyGraph> dependents = node.dependents;
final int count = dependents.size();
for (int i = 0; i < count; i++) {
final Node dependent = dependents.keyAt(i);
final SparseArray<Node> dependencies = dependent.dependencies;
dependencies.remove(key);
if (dependencies.size() == 0) {
roots.add(dependent);
}
}
}
if (index < sorted.length) {
throw new IllegalStateException("Circular dependencies cannot exist"
+ " in RelativeLayout");
}
}
- getSortedViews->findRoots:
注意dependency和dependents的词性的微妙差别,dependency是动词的名词,说明root node不依赖其它的节点;
dependents是名词,附属,说明它可能被多个节点所依赖。
关于rules可以参考:https://www.jianshu.com/p/87bc61b8a195
/**
* Finds the roots of the graph. A root is a node with no dependency and
* with [0..n] dependents.
*
* @param rulesFilter The list of rules to consider when building the
* dependencies
*
* @return A list of node, each being a root of the graph
*/
private ArrayDeque<Node> findRoots(int[] rulesFilter) {
final SparseArray<Node> keyNodes = mKeyNodes;
final ArrayList<Node> nodes = mNodes;
final int count = nodes.size();
// Find roots can be invoked several times, so make sure to clear
// all dependents and dependencies before running the algorithm
for (int i = 0; i < count; i++) {
final Node node = nodes.get(i);
node.dependents.clear();
node.dependencies.clear();
}
// Builds up the dependents and dependencies for each node of the graph
for (int i = 0; i < count; i++) {
final Node node = nodes.get(i);
final LayoutParams layoutParams = (LayoutParams) node.view.getLayoutParams();
final int[] rules = layoutParams.mRules;
final int rulesCount = rulesFilter.length;
// Look only the the rules passed in parameter, this way we build only the
// dependencies for a specific set of rules
for (int j = 0; j < rulesCount; j++) {
final int rule = rules[rulesFilter[j]];
if (rule > 0) {
// The node this node depends on
final Node dependency = keyNodes.get(rule);
// Skip unknowns and self dependencies
if (dependency == null || dependency == node) {
continue;
}
// Add the current node as a dependent
dependency.dependents.put(node, this);
// Add a dependency to the current node
node.dependencies.put(rule, dependency);
}
}
}
final ArrayDeque<Node> roots = mRoots;
roots.clear();
// Finds all the roots in the graph: all nodes with no dependencies
for (int i = 0; i < count; i++) {
final Node node = nodes.get(i);
if (node.dependencies.size() == 0) roots.addLast(node);
}
return roots;
}
其实这个算法还是挺简单的,就是根据rules,依赖与被依赖的关系来确定root nodes。
最终返回的就是不依赖任何其它的View的结点。
## 第二步:正式开始测量
0 条评论