---
title: 'State 生命週期'
disqus: kyleAlien
---
State 生命週期
===
## OverView of Content
[TOC]
## State
現在來看看 StatefulWidget#createState 方法,它會回傳一個 State,而這個 State 又如何與 Element 產生關係的
> 
### BuildContext & Element 關係
* BuildContext 實際上就是 Element 對象,它會將 Element 保護起來不讓使用者直接使用
```java=
abstract class Element extends DiagnosticableTree implements BuildContext {
... 省略
Element(Widget widget)
: assert(widget != null),
_widget = widget;
Element? _parent;
}
abstract class BuildContext {
/// The current configuration of the [Element] that is this [BuildContext].
Widget get widget;
/// The [BuildOwner] for this context. The [BuildOwner] is in charge of
/// managing the rendering pipeline for this context.
BuildOwner? get owner;
... 省略
// 數據共享的方法
T? dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({ Object? aspect });
}
```
> 
### State & Element 關係
* 在 StatefulWidget 被 inflateWidget 調用時會呼叫 createElement,創建對應的 Element 物件 (**也就是 StatefulElement**)
```java=
// framework
abstract class StatefulWidget extends Widget {
const StatefulWidget({ Key? key }) : super(key: key);
// 返回 StatefulElement 物件
@override
StatefulElement createElement() => StatefulElement(this);
@factory
State createState();
}
```
* 接下來關注 StatefulElement 物件,看它的建構函數就會看到,它會讓 ^1^ **state 持有 element**、^2^ **state 持有 Widget**
```java=
// framework
class StatefulElement extends ComponentElement {
final State<StatefulWidget> state;
StatefulElement(StatefulWidget widget)
: state = widget.createState(),
super(widget) {
... 斷言
state._element = this; // state 持有 element
... 斷言
state._widget = widget; // state 持有 Widget
}
...
}
```
> 
### State 生命週期
* 在 Flutter 框架中 State 類暴露了 7 種生命週期函數
| 函數名 | 調用時機 | 其他 |
| -------- | -------- | -------- |
| initState | 建構 | initialzed |
| didChangeDependencies | 建構 | initialzed |
| build | **建構 & 熱重載** | ready |
| reassemble | **熱重載** | ready,release 並不會被調用 |
| didUpdateWidget | **熱重載** | ready |
| deactivate | 非激活 | ready |
| dispose | 死亡 | defunct 不再有 build 能力 |
* 當 StatefulWidget 掛載成功後 (執行 mount 方法,**並且 mount 方法只會執行一次**),就會接著執行 \_firstBuild 方法,這些方法就會使用到 initState、didChangeDependencies
```java=
// framework
class StatefulElement extends ComponentElement {
@override
void _firstBuild() {
assert(state._debugLifecycleState == _StateLifecycle.created);
try {
_debugSetAllowIgnoredCallsToMarkNeedsBuild(true);
// 調用生命週期 initState
final Object? debugCheckForReturnedFuture = state.initState() as dynamic;
... 斷言
} finally {
_debugSetAllowIgnoredCallsToMarkNeedsBuild(false);
}
... 斷言
state.didChangeDependencies(); // 調用 生命週期 didChangeDependencies
super._firstBuild(); // 執行父類方法,並且最終會調用到 生命週期 build 方法
}
}
abstract class State<T extends StatefulWidget> with Diagnosticable {
@protected
@mustCallSuper
void initState() {
assert(_debugLifecycleState == _StateLifecycle.created);
}
@protected
@mustCallSuper
void didChangeDependencies() { }
}
abstract class ComponentElement extends Element {
@override
void mount(Element? parent, Object? newSlot) {
super.mount(parent, newSlot);
assert(_child == null);
assert(_lifecycleState == _ElementLifecycle.active);
_firstBuild();
assert(_child != null);
}
// StatefulElement 會 Override 這個方法
void _firstBuild() {
rebuild();
}
}
```
> 
* **updateChild 函數最終會調用 didUpdateWidget 函數**
```java=
// framework
abstract class Element extends DiagnosticableTree implements BuildContext {
Element? updateChild(Element? child, Widget? newWidget, Object? newSlot) {
... 省略部分
if (child != null) {
if (hasSameSuperclass && child.widget == newWidget) {
... 省略
} else if(hasSameSuperclass && Widget.canUpdate(child.widget, newWidget)) {
// 執行 StatefulElement#update 方法
child.update(newWidget); // 該 update 方法就會執行 didUpdateChild
} else {
deactivateChild(child); // 移除 View
newChild = inflateWidget(newWidget, newSlot); // 重新加載
}
}
... 省略部分
}
}
abstract class Widget extends DiagnosticableTree {
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType
&& oldWidget.key == newWidget.key;
}
}
class StatefulElement extends ComponentElement {
@override
void update(StatefulWidget newWidget) {
super.update(newWidget);
assert(widget == newWidget);
final StatefulWidget oldWidget = state._widget!;
_dirty = true;
state._widget = widget as StatefulWidget;
try {
_debugSetAllowIgnoredCallsToMarkNeedsBuild(true);
// 調用生命週期 didUpdateWidget !!!
final Object? debugCheckForReturnedFuture = state.didUpdateWidget(oldWidget) as dynamic;
... 斷言
} finally {
_debugSetAllowIgnoredCallsToMarkNeedsBuild(false);
}
rebuild(); // 最終會在觸發 build 方法
}
}
```
> 
### StatefulWidget 嵌套 StatefulWidget
* 觀察 **兩個 State 之間的相互作用**,把範例程式的 FloatingActionButton 抽出來,另外寫成一個 StatefulWidget
```java=
class FloatingBtn extends StatefulWidget {
@override
State<StatefulWidget> createState() => _FloatingBtnState();
}
class _FloatingBtnState extends State<FloatingBtn> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
);
}
// 省略其他生命週期函數
}
```
* **初始 - 建構順序**: MyHomePage 先建構,之後在建構 FloatingBtn
> 
* **熱重載 (ctrl + s)**: MyHomePage(父) 會先觸發 build 方法,接著才會觸發 FloatingBtn#didUpdateWidget 方法
> 
```java=
// framework
abstract class ComponentElement extends Element {
ComponentElement(Widget widget) : super(widget);
Element? _child;
@override
void performRebuild() {
Widget? built;
try {
built = build(); // MyApp 返回 MaterialApp,透過這個來切換下一個 Widget
...
} // 省略 catch、finally
try {
// 更新 Child
_child = updateChild(_child, built, slot);
assert(_child != null);
} catch (e, stack) {
...
}
...
}
}
abstract class Element extends DiagnosticableTree implements BuildContext {
// 有四種可能性,當前情況就是 有 child,接這就看是否 canUpdate
Element? updateChild(Element? child, Widget? newWidget, Object? newSlot) {
...
final Element newChild;
if (child != null) { // 4. 該元素的 Child 不為空
bool hasSameSuperclass = true;
... 斷言
if (hasSameSuperclass && child.widget == newWidget) // 創建出來的 Widget 和自身的 Child 相同
if (child.slot != newSlot)
updateSlotForChild(child, newSlot);
newChild = child; // 返回自己的 Child (省去加載)
} else if (hasSameSuperclass && Widget.canUpdate(child.widget, newWidget)) { // cnaUpdate 重點
if (child.slot != newSlot)
updateSlotForChild(child, newSlot);
// 以這個案例來說就是走這裡
child.update(newWidget);
... 斷言
newChild = child;
} else {
deactivateChild(child);
... 斷言
newChild = inflateWidget(newWidget, newSlot);
}
} else {
newChild = inflateWidget(newWidget, newSlot); // 3. inflateWidget
}
... 斷言
return newChild;
}
}
abstract class Widget extends DiagnosticableTree {
/// Initializes [key] for subclasses.
const Widget({ this.key });
// 檢查兩項條件
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType
&& oldWidget.key == newWidget.key;
}
}
```
## State 切換 & 跳轉 - 生命週期
1. 切換: 使用 Tab view 在同一個頁面跳轉
2. 跳轉: 使用 Navigator.push 跳轉頁面
### 切換 Tab & 熱重載
* 寫一個簡單的 TabView,觀察當切換不同 Tab 時,StatefulWidget 的生命週期有何變化
```java=
import 'package:flutter/material.dart';
class SimpleTab extends StatelessWidget {
static const TABS = ["GREEN", "YELLOW"];
@override
Widget build(BuildContext context) {
var tabBar = TabBar(
isScrollable: true,
labelColor: Colors.white,
unselectedLabelColor: Colors.grey,
tabs: TABS.map((e) => Container(
child: Text(e),
)).toList()
);
var tabBarView = TabBarView(
children: TABS.map((e) => _buildContext(TABS.indexOf(e))).toList()
);
return MaterialApp(
home: DefaultTabController(
length: TABS.length,
child: Scaffold(
appBar: AppBar(
title: Text('State lifecycle'),
bottom: tabBar,
),
body: tabBarView,
),
),
);
}
Widget _buildContext(int index) {
Color color = Colors.white;
Widget context = Container();
switch(index) {
case 0:
color = Colors.green;
context = GreenPage();
break;
case 1:
color = Colors.yellow;
context = YellowPage();
break;
}
Widget view = Container(
padding: EdgeInsets.only(top: 10),
alignment: Alignment.center,
color: color,
child: context,
);
return view;
}
}
class YellowPage extends StatefulWidget {
@override
State<StatefulWidget> createState() => _YellowPageState();
}
class _YellowPageState extends State<YellowPage> {
@override
Widget build(BuildContext context) {
print('YellowPage --- build');
return Text('Yellow Page');
}
@override
void initState() {
super.initState();
print('YellowPage --- initState');
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
print('YellowPage --- didChangeDependencies');
}
@override
void didUpdateWidget(YellowPage oldWidget) {
super.didUpdateWidget(oldWidget);
print('YellowPage --- didUpdateWidget');
}
@override
void reassemble() {
super.reassemble();
print('YellowPage --- reassemble');
}
@override
void deactivate() {
super.deactivate();
print('YellowPage --- deactivate');
}
@override
void dispose() {
super.dispose();
print('YellowPage --- dispose');
}
}
class GreenPage extends StatefulWidget {
@override
State<StatefulWidget> createState() => _GreenPageState();
}
class _GreenPageState extends State<GreenPage> {
@override
Widget build(BuildContext context) {
print('GreenPage --- build');
return Text('Green Page');
}
@override
void initState() {
super.initState();
print('GreenPage --- initState');
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
print('GreenPage --- didChangeDependencies');
}
@override
void didUpdateWidget(GreenPage oldWidget) {
super.didUpdateWidget(oldWidget);
print('GreenPage --- didUpdateWidget');
}
@override
void reassemble() {
super.reassemble();
print('GreenPage --- reassemble');
}
@override
void deactivate() {
super.deactivate();
print('GreenPage --- deactivate');
}
@override
void dispose() {
super.dispose();
print('GreenPage --- dispose');
}
}
```
1. 初始化會先建構第一個畫面 (GreenPage) ,^1^ initState、^2^ didChangeDependencies、^3^ build
> 
2. GreenPage -> YellowPage: 會先初始化 & 建構 Yellow 頁面,之後才會釋放 Green 頁面
> 
3. 整體切換的生命週期
> 
### 跳轉 Page - Navigator
* 使用上面的 Simple Tab 頁面,當點擊 Change Page 時就透過 Navigator 轉跳到該頁面
```java=
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
// 更新畫面
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
print('MyHomePage --- build');
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
),
TextButton(
// 跳轉到 SimpleTab 頁面
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => SimpleTab()));
},
child: Text('Change Page'),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
@override
void initState() {
print('MyHomePage --- initState');
super.initState();
}
@override
void didChangeDependencies() {
print('MyHomePage --- didChangeDependencies');
super.didChangeDependencies();
}
@override
void didUpdateWidget(MyHomePage oldWidget) {
print('MyHomePage --- didUpdateWidget');
super.didUpdateWidget(oldWidget);
}
@override
void reassemble() {
print('MyHomePage --- reassemble');
super.reassemble();
}
@override
void deactivate() {
print('MyHomePage --- deactivate');
super.deactivate();
}
@override
void dispose() {
print('MyHomePage --- dispose');
super.dispose();
}
}
```
* 先點擊 5 次,每次點擊時都會觸發 **setState 函數**,透過該函數會觸發到 build 生命週期,使其重新執行 build 函數
> 
* 跳轉頁面到 SimpleTab Page,會看到**原本的頁面 (MyHomePage) 並不會 deactivate、dispose**
> 
## setState
一開始我們在刷新畫面時,最常使用到的就是 setState 函數
```java=
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
// 刷新畫面
setState(() {
_counter++;
});
}
... 省略
}
```
setState 是 State 類中的函數
```java=
// framewrok
abstract class State<T extends StatefulWidget> with Diagnosticable {
@protected
void setState(VoidCallback fn) {
...
}
}
```
### setState - 標記 dirty
* setState 函數接收一個 VoidCallback,^1^ **引數不可為空**、^2^ **引數回傳不可以是 Future**、^3^ 最後會呼叫 markNeedsBuild 函數
```java=
// framewrok
abstract class State<T extends StatefulWidget> with Diagnosticable {
StatefulElement? _element;
@protected
void setState(VoidCallback fn) {
assert(fn != null); // 1. 斷言非空
...
final Object? result = fn() as dynamic;
assert(() {
// 2. 判斷回傳值不能是 Future
if (result is Future) {
throw FlutterError.fromParts(<DiagnosticsNode>[
...
]);
}
return true;
}());
_element!.markNeedsBuild(); // 3. 將該元素標記為需要創建
}
}
```
* markNeedsBuild 函數主要就是 ^1^ 判斷生命週期、^2^ 並將該元件設定為需要更新的狀態 (設為 dirty)、^3^ 最後呼叫 BuildOwner#scheduleBuildFor 函數
```java=
// framewrok
abstract class Element extends DiagnosticableTree implements BuildContext {
BuildOwner? get owner => _owner;
BuildOwner? _owner;
void markNeedsBuild() {
// 1. 對該元件的生命週期進行判斷
assert(_lifecycleState != _ElementLifecycle.defunct); // 該元件仍活著
if (_lifecycleState != _ElementLifecycle.active) // 如果不處於 active 則忽略不管
return;
assert(owner != null);
assert(_lifecycleState == _ElementLifecycle.active);
... 省略
if (dirty)
return;
_dirty = true; // 2. 標記為需要更新
owner!.scheduleBuildFor(this); // 3. 呼叫 BuildOwner#scheduleBuildFor 函數
}
}
class BuildOwner {
VoidCallback? onBuildScheduled;
bool _scheduledFlushDirtyElements = false;
final List<Element> _dirtyElements = <Element>[];
/// 這個註解很重要 !!!
//
/// Adds an element to the dirty elements list so that it will be rebuilt
/// when [WidgetsBinding.drawFrame] calls [buildScope].
void scheduleBuildFor(Element element) {
assert(element != null);
assert(element.owner == this);
... 省略
if (!_scheduledFlushDirtyElements && onBuildScheduled != null) {
_scheduledFlushDirtyElements = true;
onBuildScheduled!(); // 執行 Callback 回調
}
_dirtyElements.add(element); // 添加進需要更新的列表
element._inDirtyList = true;
... 省略
}
}
```
> 
:::info
* scheduleBuildFor 的註解
由於之後會觸發到 Native 函數,但目前先不接觸 Native 函數,所以看這個註解可以知道,**當使用 scheduleBuildFor 後最 ==終會呼叫到 WidgetsBinding.drawFrame 函數==**
:::
### setState - onBuildScheduled 回調 (Native)
* 透過下斷點進入 Debug 模式,可以看到它執行到 WidgetsBinding#\_handleBuildScheduled 函數
> 
* WidgetBinding 綁定請看另外一篇 [**文章**](https://hackmd.io/2Mh_c4clRhyAW7OOw9Eh_w?view#%E5%89%B5%E5%BB%BA-WidgetsFlutterBinding---ensureInitialized),這個類會在一開始建構三棵樹時就被綁定
```java=
// widgets\binding.dart
mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding {
void _handleBuildScheduled() {
... 省略斷言
ensureVisualUpdate();
}
}
```
* 最後會觸發到 **scheduleFrame 方法 (native)**,目前先分析到這裡,不繼續往下
```java=
// scheduler\binding.dart
mixin SchedulerBinding on BindingBase
SchedulerPhase get schedulerPhase => _schedulerPhase;
SchedulerPhase _schedulerPhase = SchedulerPhase.idle;
void ensureVisualUpdate() {
switch (schedulerPhase) {
case SchedulerPhase.idle:
case SchedulerPhase.postFrameCallbacks:
scheduleFrame(); // 走這裡
return;
case SchedulerPhase.transientCallbacks:
case SchedulerPhase.midFrameMicrotasks:
case SchedulerPhase.persistentCallbacks:
return;
}
}
ui.SingletonFlutterWindow get window => ui.window;
void scheduleFrame() {
if (_hasScheduledFrame || !framesEnabled)
return;
... 省略斷言
ensureFrameCallbacksRegistered();
window.scheduleFrame();
_hasScheduledFrame = true;
}
}
class SingletonFlutterWindow extends FlutterWindow {
void scheduleFrame() => platformDispatcher.scheduleFrame();
// 透過 native 渲染
void scheduleFrame() native 'PlatformConfiguration_scheduleFrame';
}
```
> 
### WidgetsBinding.drawFrame - 觸發 build
* 透過 scheduleBuildFor 的註解可以知道,**使用 scheduleBuildFor 後最 ==終會呼叫到 WidgetsBinding.drawFrame 函數==**,^1^ 經過遍歷 dirty 列表 rebuild 後、^2^ 會刷新整個頁面
```java=
// widgets\binding
mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding {
@override
void drawFrame() {
... 省略部分
try {
if (renderViewElement != null)
buildOwner!.buildScope(renderViewElement!); // 1. 依照 dirty 列表 rebuild
// 呼叫到 RendererBinding#drawFrame
super.drawFrame(); // 2. flush layout、paint、compositingBit ..
buildOwner!.finalizeTree();
} finally {
assert(() {
debugBuildingDirtyElements = false;
return true;
}());
}
... 省略部分
}
// framework
class BuildOwner {
void buildScope(Element context, [ VoidCallback? callback ]) {
... 省略部分
while (index < dirtyCount) {
... 省略斷言
try {
_dirtyElements[index].rebuild(); // Element#rebuild 函數,最終會呼叫到 build 函數
} catch (e, stack) {
...
}
index += 1;
if (dirtyCount < _dirtyElements.length || _dirtyElementsNeedsResorting!) {
_dirtyElements.sort(Element._sort); // 重新排序,dirty list
_dirtyElementsNeedsResorting = false;
dirtyCount = _dirtyElements.length;
while (index > 0 && _dirtyElements[index - 1].dirty) {
index -= 1;
}
}
}
}
}
// rendering\binding.dart
mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, SemanticsBinding, HitTestable {
@protected
void drawFrame() { // 刷新各種 View
assert(renderView != null);
pipelineOwner.flushLayout();
pipelineOwner.flushCompositingBits();
pipelineOwner.flushPaint();
if (sendFramesToEngine) {
renderView.compositeFrame(); // this sends the bits to the GPU
pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
_firstFrameSent = true;
}
}
}
```
> 
### RendererBinding 重繪製
* WidgetsBinding#drawFrame 觸發的第二個方法最終會到達 RendererBinding#drawFrame 函數
```java=
// widgets\binding
mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding {
@override
void drawFrame() {
... 省略部分
try {
if (renderViewElement != null)
buildOwner!.buildScope(renderViewElement!); // 1. 依照 dirty 列表 rebuild
// 呼叫到 RendererBinding#drawFrame
super.drawFrame(); // 2. flush layout、paint、compositingBit ..
buildOwner!.finalizeTree();
} finally {
assert(() {
debugBuildingDirtyElements = false;
return true;
}());
}
... 省略部分
}
// rendering\binding.dart
mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, SemanticsBinding, HitTestable {
PipelineOwner get pipelineOwner => _pipelineOwner;
late PipelineOwner _pipelineOwner;
@protected
void drawFrame() { // 刷新各種 View
assert(renderView != null);
pipelineOwner.flushLayout();
pipelineOwner.flushCompositingBits();
pipelineOwner.flushPaint();
if (sendFramesToEngine) {
renderView.compositeFrame(); // this sends the bits to the GPU
pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
_firstFrameSent = true;
}
}
}
```
* 這裡分三個步驟,flushLayout、flushCompositingBits、flushPaint
1. **flushLayout**: 最終會呼叫到 RenderObject#performLayout,**重新布局**
```java=
// rendering\object
class PipelineOwner {
List<RenderObject> _nodesNeedingLayout = <RenderObject>[];
void flushLayout() {
... 省略部分
try {
while (_nodesNeedingLayout.isNotEmpty) {
final List<RenderObject> dirtyNodes = _nodesNeedingLayout;
_nodesNeedingLayout = <RenderObject>[];
// 按照 view 的深度調整 Render Object List
for (final RenderObject node in dirtyNodes..sort((RenderObject a, RenderObject b) => a.depth - b.depth)) {
if (node._needsLayout && node.owner == this)
node._layoutWithoutResize(); // 走這裡
}
}
} finally {
... 省略部分
}
}
abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin implements HitTestTarget {
void _layoutWithoutResize() {
... 省略斷言
try {
performLayout();
markNeedsSemanticsUpdate();
} catch (e, stack) {
_debugReportException('performLayout', e, stack);
}
... 省略斷言
_needsLayout = false;
markNeedsPaint();
}
void performLayout();
}
```
> 
2. flushCompositingBits: 最終會呼叫到 RenderObject#\_updateCompositingBits 方法
```java=
// rendering\object
class PipelineOwner {
final List<RenderObject> _nodesNeedingCompositingBitsUpdate = <RenderObject>[];
void flushCompositingBits() {
if (!kReleaseMode) {
Timeline.startSync('Compositing bits');
}
// 按照 view 的深度調整 Render Object List
_nodesNeedingCompositingBitsUpdate.sort((RenderObject a, RenderObject b) => a.depth - b.depth);
for (final RenderObject node in _nodesNeedingCompositingBitsUpdate) {
if (node._needsCompositingBitsUpdate && node.owner == this)
node._updateCompositingBits();
}
_nodesNeedingCompositingBitsUpdate.clear();
if (!kReleaseMode) {
Timeline.finishSync();
}
}
}
abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin implements HitTestTarget {
void _updateCompositingBits() {
if (!_needsCompositingBitsUpdate)
return;
final bool oldNeedsCompositing = _needsCompositing;
_needsCompositing = false;
visitChildren((RenderObject child) { // 更新子類的 _updateCompositingBits
child._updateCompositingBits();
if (child.needsCompositing)
_needsCompositing = true;
});
... 省略部分
}
void visitChildren(RenderObjectVisitor visitor) { }
}
```
> 
3. flushPaint: 重新繪製,最終會呼叫到 RenderObject#Paint 方法
```java=
// rendering\object
class PipelineOwner {
void flushPaint() {
... 省略部分
try {
final List<RenderObject> dirtyNodes = _nodesNeedingPaint;
_nodesNeedingPaint = <RenderObject>[];
// Sort the dirty nodes in reverse order (deepest first).
for (final RenderObject node in dirtyNodes..sort((RenderObject a, RenderObject b) => b.depth - a.depth)) {
assert(node._layer != null);
if (node._needsPaint && node.owner == this) {
if (node._layer!.attached) {
PaintingContext.repaintCompositedChild(node); // 重新繪製
} else {
node._skippedPaintingOnLayer();
}
}
}
assert(_nodesNeedingPaint.isEmpty);
} finally {
... 省略部分
}
}
}
class PaintingContext extends ClipContext {
static void repaintCompositedChild(RenderObject child, { bool debugAlsoPaintedParent = false }) {
assert(child._needsPaint);
_repaintCompositedChild(
child,
debugAlsoPaintedParent: debugAlsoPaintedParent,
);
}
static void _repaintCompositedChild(
RenderObject child, {
bool debugAlsoPaintedParent = false,
PaintingContext? childContext,
}) {
... 省略部分
childContext ??= PaintingContext(child._layer!, child.paintBounds);
child._paintWithContext(childContext, Offset.zero);
... 省略部分
}
}
abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin implements HitTestTarget {
void _paintWithContext(PaintingContext context, Offset offset) {
... 省略部分
if (_needsLayout)
return;
try {
paint(context, offset); // 重新繪製
... 省略斷言
} catch (e, stack) {
_debugReportException('paint', e, stack);
}
... 省略部分
}
void paint(PaintingContext context, Offset offset) { }
}
```
> 
## Appendix & FAQ
:::info
flushCompositingBits 的功能 ?
:::
###### tags: `Flutter`