Flutterにおいてmain関数で実行されるrunApp関数の実装を読んでいきます。
参照バージョン: Flutter 2.8.0
ドキュメントコメントの確認
- 引数のウィジェットを広げて画面に貼り付ける。
- 画面全体を埋めるようにウィジェットに制約を与える。
- 片側に寄せたり中央に配置する場合はAlignやCenterウィジェットを利用する。
- runAppを2回呼ぶと前回のウィジェットを画面から切り離し、新しいウィジェットが利用される。
runAppの実装
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
..scheduleAttachRootWidget(app)
..scheduleWarmUpFrame();
}
WidgetsFlutterBinding.ensureInitialized
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding.instance == null)
WidgetsFlutterBinding();
return WidgetsBinding.instance!;
}
WidgetsFlutterBinding.ensureInitialized
は作成・初期化されたWidgetsBindingのインスタンスを返します。main関数でrunApp以前にWidgetsFlutterBinding.ensureInitialized
を実行することがよくありますが、最初の実行でWidgetsFlutterBinding()
イニシャライザが実行されインスタンスが作成されます。2回目以降は初期化された WidgetsBinding.instance
が既に作成されており、それを返すだけの挙動になります。このイニシャライザは親クラスのBindingBaseで定義されています。BindingBaseはシングルトンサービスを提供するmixinのベースクラスです。initInstances
で初期化を行いinitServiceExtensions
で必要があればobservatory service extensionを初期化しています。WidgetsFlutterBindingは以下のmixinを付与されています。
- GestureBinding(ジェスチャーサブシステムのためのバインディング)
- SchedulerBinding(Post-frame callbackなどを実行するためのスケジューラ)
- ServicesBinding(プラットフォームのメッセージをリッスンしdefaultBinaryMessengerに送信する)
- PaintingBinding(ペイントライブラリ用のバインディング)
- SemanticsBinding(セマンティクスレイヤーとFlutterエンジンを接続する)
- RendererBinding(レンダーツリーとFlutterエンジンを接続する)
- WidgetsBinding(ウィジェットレイヤーとFlutterエンジンを接続する)
これらのinitInstances
とinitServiceExtensions
が呼ばれます。
WidgetsFlutterBinding.ensureInitialized
はFlutterエンジンとの接続やスケジューラなどのバイディングの初期化をおこなっていると言えます。
scheduleAttachRootWidget
初期化の次に実行されるscheduleAttachRootWidget
では、TimerでスケジュールしてattachRootWidgetメソッドによりルートウィジェットをアタッチしています。attachRootWidgetメソッド直接呼べば同期的にウィジェットツリーを構築できるということですが、ここではTimerを利用して非同期的に構築しています。attachRootWidget
メソッドは受け取ったウィジェットをrenderViewElementにアタッチしてウィジェットツリーを構築します。renderViewElementはElementクラスでヒエラルキーのルートです。
scheduleWarmUpFrame
ドキュメントコメントから
- システムのVsyncシグナルへ応答してエンジンがフレームをリクエストするのを待つのではなく、可能な限り早くフレームを実行するようにスケジュールしている。
- アプリケーションの起動時に利用される。
- 非常に効果になる可能性がある最初のフレームが数ミリ秒余分に実行されるようにしている。
- スケジュールされたフレームが完了するまでイベントのディスパッチをロックしている。
runAppのまとめ
runAppは以下のタスクを行なっています。
- Flutterエンジンとの接続やスケジューラなどのバインディングの初期化
- ウィジェットツリーの構築(のスケジューリング)
- 最初のフレームの実行(のスケジューリング)