markNeedsBuild「再構築、必要、マークつけとくから頼んだ🙋♂️」
Elementが「再構築(rebuild)が必要(Needs)になりました🙋♂️」とrebuildを希望します。
rebuildを希望するElementは自身にマーク(mark)をつける決まりになっています。
(ここからは再構築とrebuildはrebuildで統一して表現します)
解説していきます。
マークとは具体的に何?
=> Elementが持つpropertyのdirty(bool)のことです
https://api.flutter.dev/flutter/widgets/Element-class.html#:~:text=read%2Donly-,dirty,-%E2%86%92%20bool
dirtyとは?
=> Elementの持つpropertyで型はboolです。
要素が再構築が必要であるとマークされている場合はtrueを返します。(google翻訳)
https://api.flutter.dev/flutter/widgets/Element/dirty.html
雰囲気を実際のコードで伝えます
class Element {
//...
/// Returns true if the element has been marked as needing rebuilding.
bool get dirty => _dirty;
bool _dirty = true;
//....
}
ここまでがmarkNeedsBuildの簡単な説明です。
Q&A形式で理解を深める
ここからはmarkNeedsBuildが
flutterの他の機能とどのように関わり
何を実現するかなどをQ&A形式で書いていきます
rebuildは誰に要請するの?
=> BuildOwnerクラスです。
BuildOwnerクラスとは何?
=> Elementツリーを管理するクラスです
rebuildはBuildOwnerクラスのどこでされるの?
=> BuildOwnerのbuildScopeメソッドです
フレーム毎に呼ばれるdrawFrameがbuildScopeを呼び出すようです。
markNeedsBuildのメソッドの中身は?何をしているの?
=> dirtyをtrueにしBuildOwnerのクラスのscheduleBuildForメソッドを呼びます。引数は自身(Element)
まずBuildOwnerのクラスのscheduleBuildForメソッドの説明をします
=> _dirtyElementsというprivateなpropertyに引数として渡されたElementを追加します
_dirtyElementsとはrebuild待ちElementリストのことです。
(まとめます)markNeedsBuildのメソッドの中身は?何をしているの?
ElementのmarkNeedsBuildメソッドの処理の流れを見てみましょう
1,ElementクラスのmarkNeedsBuildメソッドは
BuildOwnerクラスのscheduleBuildForメソッドを呼び出します。
引数として自身(Element)を渡します。
2,呼び出されたBuildOwnerクラスのscheduleBuildForメソッドは渡されたElementを
rebuild待ちElementリストである_dirtyElementsプロパティに追加します。
少々複雑な説明になってしまったので
最低限必要な部分のみを切り出した簡単なコードを見てみましょう
Element
//色々と省略...
void markNeedsBuild() {
//色々と省略...
_dirty = true;
owner!.scheduleBuildFor(this); //1
}
BuildOwner
//色々と省略...
final List<Element> _dirtyElements = <Element>[];
void scheduleBuildFor(Element element) {
//色々と省略...
_dirtyElements.add(element); //2
}
その_dirtyElementsはその後どのように使われるの?
=> フレーム毎に呼ばれるWidgetBindingのdrawFrameがBuildOwnerのbuildScopeを呼び出しrebuild待ちElementリストである_dirtyElementsを順に取り出しrebuildしていきます
buildScopeのコードを見てみる(抜粋し4行にした)
for (final Element element in _dirtyElements) {
//...
try {
element.rebuild();
} catch (e, stack) {
// ...
}
//...
}
気になる方はgithubで確認してみて下さい。