runAppを読む

runAppを読む
Photo by Vojtech Bruzek / Unsplash

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エンジンを接続する)

これらのinitInstancesinitServiceExtensionsが呼ばれます。

WidgetsFlutterBinding.ensureInitializedはFlutterエンジンとの接続やスケジューラなどのバイディングの初期化をおこなっていると言えます。

scheduleAttachRootWidget

初期化の次に実行されるscheduleAttachRootWidgetでは、TimerでスケジュールしてattachRootWidgetメソッドによりルートウィジェットをアタッチしています。attachRootWidgetメソッド直接呼べば同期的にウィジェットツリーを構築できるということですが、ここではTimerを利用して非同期的に構築しています。attachRootWidgetメソッドは受け取ったウィジェットをrenderViewElementにアタッチしてウィジェットツリーを構築します。renderViewElementはElementクラスでヒエラルキーのルートです。

scheduleWarmUpFrame

ドキュメントコメントから

  • システムのVsyncシグナルへ応答してエンジンがフレームをリクエストするのを待つのではなく、可能な限り早くフレームを実行するようにスケジュールしている。
  • アプリケーションの起動時に利用される。
  • 非常に効果になる可能性がある最初のフレームが数ミリ秒余分に実行されるようにしている。
  • スケジュールされたフレームが完了するまでイベントのディスパッチをロックしている。

runAppのまとめ

runAppは以下のタスクを行なっています。

  1. Flutterエンジンとの接続やスケジューラなどのバインディングの初期化
  2. ウィジェットツリーの構築(のスケジューリング)
  3. 最初のフレームの実行(のスケジューリング)