Flutter setState为什么不会造成性能困扰?
2020-04-10 本文已影响0人
mtko
setState为什么不会造成性能困扰?
因为只更新当前图层树。
flutter是怎么做element diff,做到只布局、绘制、合成差异部分视图的?
见以下代码
核心代码
Flutter版本
Flutter: 1.12.13+hotfix.8
核心类
abstract class RenderObject
widget层调用
setState();
核心数据结构
链表
遍历链表寻找relayout boundary,重新布局
void markNeedsLayout() {
assert(_debugCanPerformMutations);
if (_needsLayout) {
assert(_debugSubtreeRelayoutRootAlreadyMarkedNeedsLayout());
return;
}
assert(_relayoutBoundary != null);
if (_relayoutBoundary != this) {
markParentNeedsLayout();
} else {
_needsLayout = true;
if (owner != null) {
assert(() {
if (debugPrintMarkNeedsLayoutStacks)
debugPrintStack(label: 'markNeedsLayout() called for $this');
return true;
}());
owner._nodesNeedingLayout.add(this);
owner.requestVisualUpdate();
}
}
}
遍历链表检查renderObject是否是重绘边界(isRepaintBoundary = true)时,决定合成范围
void markNeedsCompositingBitsUpdate() {
if (_needsCompositingBitsUpdate)
return;
_needsCompositingBitsUpdate = true;
if (parent is RenderObject) {
final RenderObject parent = this.parent;
if (parent._needsCompositingBitsUpdate)
return;
if (!isRepaintBoundary && !parent.isRepaintBoundary) {
parent.markNeedsCompositingBitsUpdate();
return;
}
}
assert(() {
final AbstractNode parent = this.parent;
if (parent is RenderObject)
return parent._needsCompositing;
return true;
}());
// parent is fine (or there isn't one), but we are dirty
if (owner != null)
owner._nodesNeedingCompositingBitsUpdate.add(this);
}
遍历链表检查renderObject是否是重绘边界(isRepaintBoundary = true),决定绘制范围,或 没有标记isRepaintBoundary的RenderObject时全部绘制
void markNeedsPaint() {
assert(owner == null || !owner.debugDoingPaint);
if (_needsPaint)
return;
_needsPaint = true;
if (isRepaintBoundary) {
assert(() {
if (debugPrintMarkNeedsPaintStacks)
debugPrintStack(label: 'markNeedsPaint() called for $this');
return true;
}());
// If we always have our own layer, then we can just repaint
// ourselves without involving any other nodes.
assert(_layer is OffsetLayer);
if (owner != null) {
owner._nodesNeedingPaint.add(this);
owner.requestVisualUpdate();
}
} else if (parent is RenderObject) {
final RenderObject parent = this.parent;
parent.markNeedsPaint();
assert(parent == this.parent);
} else {
assert(() {
if (debugPrintMarkNeedsPaintStacks)
debugPrintStack(label: 'markNeedsPaint() called for $this (root of render tree)');
return true;
}());
// If we're the root of the render tree (probably a RenderView),
// then we have to paint ourselves, since nobody else can paint
// us. We don't add ourselves to _nodesNeedingPaint in this
// case, because the root is always told to paint regardless.
if (owner != null)
owner.requestVisualUpdate();
}
}
结语:
1.setState的节点越远离根部,布局、合成、绘制的开销越少
2.重写isRepaintBoundary可变化绘制范围,可影响开销;如使用RepaintBoundary
部件
3.绝对宽高可减少开销(constraints.isTight)
RenderObject relayoutBoundary;
if (!parentUsesSize || sizedByParent || constraints.isTight || parent is! RenderObject) {
relayoutBoundary = this;
} else {
final RenderObject parent = this.parent;
relayoutBoundary = parent._relayoutBoundary;
}