<

ホットリロード

Flutter のホット リロード機能は、迅速かつ迅速な作業に役立ちます。 実験、UI の構築、機能の追加、バグの修正が簡単に行えます。 ホットリロードは、更新されたソースコードファイルを挿入することで機能します ランニング中Dart 仮想マシン (VM)。 VM がフィールドと関数の新しいバージョンでクラスを更新した後、 Flutter フレームワークはウィジェット ツリーを自動的に再構築します。 変更の効果をすぐに確認できるようになります。

ホットリロードを実行する方法

Flutter アプリをホットリロードするには:

  1. サポートされている環境からアプリを実行する flutterエディターまたはターミナルウィンドウ。 物理デバイスまたは仮想デバイスのいずれかをターゲットにすることができます。デバッグ モードの Flutter アプリのみがホット リロードまたはホット リスタートできます。
  2. プロジェクト内の Dart ファイルの 1 つを変更します。 ほとんどの種類のコード変更はホットリロードできます。 ホットリスタートが必要な変更のリストについては、 見る特殊なケース
  3. Flutter の IDE ツールをサポートする IDE/エディターで作業している場合は、 選択するすべてを救う(cmd-s/ctrl-s)、 または、ツールバーのホットリロードボタンをクリックします。

    コマンドラインでアプリを実行している場合、flutter run、 入力rターミナルウィンドウで。

ホットリロード操作が成功した後、 コンソールに次のようなメッセージが表示されます。

Performing hot reload...
Reloaded 1 of 448 libraries in 978ms.

アプリは変更を反映して更新されます。 アプリの現在の状態は保持されます。 アプリは以前の状態から引き続き実行されます ホットリロードコマンドを実行します。 コードが更新され、実行が続行されます。

Android Studio UI
Android Studio での実行、デバッグ実行、ホットリロード、ホットリスタートのコントロール

コードの変更は、変更された場合にのみ目に見える効果をもたらします。 Dart コードは変更後に再度実行されます。具体的には、 ホット リロードにより、既存のすべてのウィジェットが再構築されます。 ウィジェットの再構築に関与するコードのみ 自動的に再実行されます。のmain()initState()たとえば、関数は再度実行されません。

特殊なケース

次のセクションでは、次のような具体的なシナリオについて説明します。 ホットリロード。場合によっては、Dart コードに小さな変更を加える アプリでホット リロードを引き続き使用できるようになります。 他の場合には、ホットリスタートまたは完全な再起動が必要になります。

アプリが強制終了されました

アプリが強制終了されるとホットリロードが中断される可能性があります。 たとえば、アプリがバックグラウンドで長時間動作していた場合などです。

コンパイルエラー

コードの変更によりコンパイル エラーが発生すると、 ホット リロードでは、次のようなエラー メッセージが生成されます。

Hot reload was rejected:
'/path/to/project/lib/main.dart': warning: line 16 pos 38: unbalanced '{' opens here
  Widget build(BuildContext context) {
                                     ^
'/path/to/project/lib/main.dart': error: line 33 pos 5: unbalanced ')'
    );
    ^

この状況では、単にエラーを修正してください。 ホットリロードを使用し続けるための Dart コードの指定行。

CupertinoTabView のビルダー

ホットリロードでは、行われた変更は適用されません あるbuilderCupertinoTabView。 詳細については、を参照してください。問題 43574。

列挙型

列挙型が次の場合、ホット リロードは機能しません。 通常クラスへの変更、または通常クラスへの変更 列挙型に変更されました。

例えば:

変更前:

enum Color {
  red,
  green,
  blue,
}

変更後:

class Color {
  Color(this.i, this.j);
  final int i;
  final int j;
}

ジェネリックタイプ

ジェネリック型宣言の場合、ホット リロードは機能しません 変更されています。たとえば、次のような場合は機能しません。

変更前:

class A<T> {
  T? i;
}

変更後:

class A<T, V> {
  T? i;
  V? v;
}

ネイティブコード

ネイティブ コード (Kotlin、Java、Swift など) を変更した場合、 または Objective-C)、完全な再起動 (停止および アプリを再起動します)変更が有効になることを確認します。

以前の状態が新しいコードと結合されます

Flutter のステートフル ホット リロードはアプリの状態を保存します。 このアプローチにより、ほとんどの効果を確認できます。 現在の状態を破棄せずに、最近の変更のみを表示します。 たとえば、アプリでユーザーのログインが必要な場合、 ページを数レベル下で変更およびホットリロードできます。 ログイン資格情報を再入力することなく、ナビゲーション階層にアクセスできます。 状態は維持されます。これは通常、望ましい動作です。

コードの変更がアプリ (またはその依存関係) の状態に影響を与える場合、 アプリが扱う必要があるデータは完全に一貫していない可能性があります 最初から実行した場合に得られるデータを使用します。 ホットリロード後の動作は異なる可能性があります ホットリスタートとの比較。

最近のコード変更は含まれますが、アプリの状態は除外されます

ダーツでは、静的フィールドは遅延して初期化されます。 これは、初めて Flutter アプリを実行し、 静的フィールドが読み取られると、その値に設定されます。 初期化子は次のように評価されました。 グローバル変数と静的フィールドは状態として扱われます。 したがって、ホットリロード中に再初期化されません。

グローバル変数と静的フィールドの初期化子を変更すると、 ホットリスタート、またはイニシャライザが保持されている状態を再起動します。 変化を確認するには必要です。 たとえば、次のコードを考えてみましょう。

final sampleTable = [
  Table(
    children: const [
      TableRow(
        children: [Text('T1')],
      )
    ],
  ),
  Table(
    children: const [
      TableRow(
        children: [Text('T2')],
      )
    ],
  ),
  Table(
    children: const [
      TableRow(
        children: [Text('T3')],
      )
    ],
  ),
  Table(
    children: const [
      TableRow(
        children: [Text('T4')],
      )
    ],
  ),
];

アプリを実行した後、次の変更を加えます。

final sampleTable = [
  Table(
    children: const [
      TableRow(
        children: [Text('T1')],
      )
    ],
  ),
  Table(
    children: const [
      TableRow(
        children: [Text('T2')],
      )
    ],
  ),
  Table(
    children: const [
      TableRow(
        children: [Text('T3')],
      )
    ],
  ),
  Table(
    children: const [
      TableRow(
        children: [Text('T10')], // modified
      )
    ],
  ),
];

ホットリロードを実行しましたが、変更が反映されません。

逆に、次の例では:

const foo = 1;
final bar = foo;
void onClick() {
  print(foo);
  print(bar);
}

アプリを初めて実行すると印刷される11。 次に、次の変更を加えます。

const foo = 2; // modified
final bar = foo;
void onClick() {
  print(foo);
  print(bar);
}

に変化する間、constフィールド値は常にホットリロードされます。 静的フィールド初期化子は再実行されません。概念的には、constフィールドは状態ではなくエイリアスのように扱われます。

Dart VM はイニシャライザの変更を検出し、セットが変更されたときにフラグを立てます。 変更を有効にするにはホットリスタートが必要です。 フラグ設定メカニズムがトリガーされるのは、 上記の例では、初期化作業の大部分が行われます。 ただし、次のような場合は除きます。

final bar = foo;

更新するにはfooホットリロード後の変更を表示します。 フィールドを次のように再定義することを検討してください。constまたはゲッターを使用して を使用するのではなく、値を返しますfinal。 たとえば、次のいずれかの解決策が機能します。

const foo = 1;
const bar = foo; // Convert foo to a const...
void onClick() {
  print(foo);
  print(bar);
}
const foo = 1;
int get bar => foo; // ...or provide a getter.
void onClick() {
  print(foo);
  print(bar);
}

詳細については、「違い 間にconstfinalキーワードダーツで。

最近のUI変更は除く

ホット リロード操作が成功したように見えても、何も生成されない場合でも、 例外として、一部のコード変更は、更新された UI に表示されない場合があります。 この動作は、アプリの変更後によく見られます。main()またinitState()方法。

原則として、変更されたコードがルートの下流にある場合、 ウィジェットのbuild()メソッドを実行すると、ホット リロードは期待どおりに動作します。 ただし、変更されたコードが結果として再実行されない場合は、 ウィジェット ツリーを再構築しないと、 ホットリロード後の効果を確認してください。

たとえば、次のコードを考えてみましょう。

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return GestureDetector(onTap: () => print('tapped'));
  }
}

このアプリを実行した後、コードを次のように変更します。

import 'package:flutter/widgets.dart';

void main() {
  runApp(const Center(child: Text('Hello', textDirection: TextDirection.ltr)));
}

ホットリスタートではプログラムが最初から始まり、 新しいバージョンを実行しますmain()、 テキストを表示するウィジェット ツリーを構築しますHello

ただし、この変更後にアプリをホットリロードすると、main()initState()再実行されず、 ウィジェット ツリーは変更されていないインスタンスで再構築されます。 のMyAppルートウィジェットとして。 このため、ホット リロード後に目に見える変化は見られません。

使い方

ホット リロードが呼び出されると、ホスト マシンは次のようになります。 前回のコンパイル以降に編集されたコード。 次のライブラリが再コンパイルされます。

  • コードが変更されたライブラリ
  • アプリケーションのメインライブラリ
  • 主要な図書館からの図書館 影響を受けるライブラリへ

これらのライブラリのソース コードは次のようにコンパイルされます。カーネルファイルそしてモバイルデバイスの Dart VM に送信されます。

Dart VM は、新しいカーネル ファイルからすべてのライブラリを再ロードします。 これまでのところ、コードは再実行されていません。

ホット リロード メカニズムにより、Flutter フレームワークが起動されます。 既存のすべての再構築/再レイアウト/再ペイントをトリガーするには ウィジェットとレンダリング オブジェクト。