做自(zì)由與創造的先行者

Flutter 使用(yòng)熱重載

Flutter開(kāi)發手冊

使用(yòng)熱重載

Flutter的熱重載(hot reload)功能(néng)可以幫助您在無需重新啓動應用(yòng)的情況下(xià)快(kuài)速、輕松地進行測試、構建用(yòng)戶界面、添加功能(néng)以及修複錯誤。 通過将更新後的源代碼文(wén)件注入正在運行的Dart虛拟機(VM)中來(lái)實現(xiàn)熱重載。在虛拟機使用(yòng)新的的字段和(hé)函數更新類後,Flutter框架會(huì)自(zì)動重新構建widget樹,以便您快(kuài)速查看(kàn)更改的效果。

要熱重載一個Flutter應用(yòng)程序:

從(cóng)受支持的IntelliJ IDE或終端窗口運行應用(yòng)程序。物理(lǐ)機或虛拟器都可以運行。

修改項目中的一個Dart文(wén)件。大(dà)多數類型的代碼更改可以重新加載;

如果您使用(yòng)的是IntelliJ IDE,請(qǐng)選擇Save All (cmd-s/ctrl-s)),或者單擊工(gōng)具欄上(shàng)的Hot Reload按鈕。alt_text

如果您正在使用(yòng)命令行flutter run運行應用(yòng)程序,請(qǐng)在終端窗口輸入r

成功執行熱重載後,您将在控制台中看(kàn)到(dào)類似于以下(xià)内容的消息:

Performing hot reload...

Reloaded 1 of 448 libraries in 2,777ms.

應用(yòng)程序已更新以反映您的更改,并且該應用(yòng)程序的當前狀态(以上(shàng)示例中的計(jì)數器變量的值)将保留。您的應用(yòng)程序将繼續執行之前運行熱重載命令的位置。代碼被更新并繼續執行。

A code change has a visible effect only if the modified Dart code is run again after the change. The next sections describe common situations where the modified code will not run again after hot reload. In some cases, small changes to the Dart code will enable you to continue using hot reload for your app. 隻有修改後的Dart代碼再次運行時(shí),代碼更改才會(huì)有效果。接下(xià)來(lái)的部分将介紹常見的情況,即修改後的代碼在熱重載後不會(huì)再運行。 在某些(xiē)情況下(xià),對(duì)Dart代碼的小(xiǎo)改動将使您能(néng)夠繼續爲您的應用(yòng)程序使用(yòng)熱重新加載。

編譯錯誤

當代碼更改後引入了(le)編譯錯誤時(shí),熱重載會(huì)生成類似于以下(xià)内容的錯誤消息

Hot reload was rejected:

'/Users/obiwan/Library/Developer/CoreSimulator/Devices/AC94F0FF-16F7-46C8-B4BF-218B73C547AC/data/Containers/Data/Application/4F72B076-42AD-44A4-A7CF-57D9F93E895E/tmp/ios_testWIDYdS/ios_test/lib/main.dart': warning: line 16 pos 38: unbalanced '{' opens here

Widget build(BuildContext context) {

^

'/Users/obiwan/Library/Developer/CoreSimulator/Devices/AC94F0FF-16F7-46C8-B4BF-218B73C547AC/data/Containers/Data/Application/4F72B076-42AD-44A4-A7CF-57D9F93E895E/tmp/ios_testWIDYdS/ios_test/lib/main.dart': error: line 33 pos 5: unbalanced ')'

);

^

在這(zhè)種情況下(xià),隻需糾正代碼錯誤,就可以繼續使用(yòng)熱重載。

之前的狀态與新代碼結合在一起

Flutter的熱重載功能(néng)(有時(shí)稱爲有_狀态熱重載_)可保留您的應用(yòng)程序的狀态。這(zhè)種設計(jì)使您隻能(néng)查看(kàn)最近更改的效果,而不會(huì)丢棄當前狀态。 例如,如果您的應用(yòng)需要用(yòng)戶登錄,則可以在導航層次結構中向下(xià)幾個級别修改并重新加載頁面,而無需重新輸入登錄憑據。狀态保持不變,這(zhè)通常是期望的行爲。

如果代碼更改會(huì)影響應用(yòng)程序(或其依賴)的狀态,則應用(yòng)程序必須使用(yòng)的數據可能(néng)與它從(cóng)頭開(kāi)始執行的數據不完全一緻。在熱重載和(hé)完全重啓之後,結果可能(néng)是不同的行爲。 例如,如果您将某個StatelessWidget類改爲StatefulWidget(或相反),則在熱重載之後,應用(yòng)程序的以前狀态将保留。但(dàn)是,該狀态可能(néng)與新的更改不兼容。

考慮下(xià)面的代碼:

class myWidget extends StatelessWidget {

Widget build(BuildContext context) {

return new GestureDetector(onTap: () => print('T'));

}

}

運行該應用(yòng)程序後,如果進行以下(xià)更改:

class myWidget extends StatefulWidget {

@override

State createState() => new myWidgetState();

}

class myWidgetState {

...

...

}

然後熱重載,控制台将顯示類似于以下(xià)内容的斷言失敗:

myWidget is not a subtype of StatelessWidget

在這(zhè)些(xiē)情況下(xià),需要完全重新啓動以查看(kàn)更新的應用(yòng)程序.

包含最近的代碼更改,但(dàn)排除了(le)應用(yòng)程序狀态

在Dart中,靜态字段惰性初始化。 這(zhè)意味着你(nǐ)第一次運行一個Flutter應用(yòng)程序并讀取一個靜态字段時(shí),它的初始值設爲初始表達式的結果。全局變量和(hé)靜态字段被視(shì)爲狀态,因此在熱重載期間不會(huì)重新初始化。

如果更改全局變量和(hé)靜态字段的初始值設定項,則需要完全重啓以查看(kàn)更改。例如,請(qǐng)考慮以下(xià)代碼

final sampleTable = [

new Table("T1"),

new Table("T2"),

new Table("T3"),

new Table("T4"),

];

運行該應用(yòng)程序後,如果進行以下(xià)更改:

final sampleTable = [

new Table("T1"),

new Table("T2"),

new Table("T3"),

new Table("T10"), //modified

];

然後熱重載,這(zhè)個改變并沒有生效

相反,在下(xià)面的例子中:

const foo = 1;

final bar = foo;

void onClick(){

print(foo);

print(bar);

}

第一次運行應用(yòng)程序打印1和(hé)1。然後,如果您進行以下(xià)更改:

const foo = 2; //modified

final bar = foo;

void onClick(){

print(foo);

print(bar);

}

然後熱重載,它現(xiàn)在打印2和(hé)1。對(duì)const字段值的更改始終會(huì)重新加載,但(dàn)不會(huì)重新運行靜态字段初始值設定語句(初始值可能(néng)是一個表達式的值)。 從(cóng)概念上(shàng)講,const字段被視(shì)爲别名而不是狀态。

Dart VM在一組更改需要完全重啓才能(néng)生效的時(shí)候,會(huì)檢測初始化程序更改和(hé)标志。上(shàng)述示例中的大(dà)部分初始化工(gōng)作(zuò)都會(huì)觸發标記機制,但(dàn)不适用(yòng)于以下(xià)情況:

final bar = foo;

要能(néng)夠在熱重載後更新和(hé)查看(kàn)foo的更改,請(qǐng)考慮将字段重新定義爲const或使用(yòng)getter來(lái)返回值,而不是使用(yòng)final。例如:

const bar = foo;

or:

get bar => foo;

最近的UI更改被排除在外(wài)

即使熱重載操作(zuò)看(kàn)起來(lái)成功了(le)并且沒有抛出異常,但(dàn)某些(xiē)代碼更改可能(néng)在刷新的UI中不可見。這(zhè)種行爲在更改應用(yòng)程序的main()方法後很(hěn)常見。

作(zuò)爲一般規則,如果修改後的代碼位于根widget的構建方法的下(xià)遊,則熱重載将按預期運行。但(dàn)是,如果修改後的代碼不會(huì)因重建構建widget樹而重新執行的話(huà),那麽在熱重載後您将看(kàn)不到(dào)其效果。

例如,請(qǐng)考慮以下(xià)代碼:

import 'package:flutter/material.dart';

void main() {

runApp(new MyApp());

}

class MyApp extends StatelessWidget {

Widget build(BuildContext context) {

return new GestureDetector(

onTap: () => print('tapped'));

}

}

運行這(zhè)個應用(yòng)程序後,您可能(néng)會(huì)更改代碼,如下(xià)所示:

import 'package:flutter/widgets.dart';

void main() {

runApp(

const Center(

child: const Text('Hello', textDirection: TextDirection.ltr)));

}

完全重啓後,程序從(cóng)頭開(kāi)始執行新版本main(),并構建一個widget樹顯示文(wén)本”Hello”。

但(dàn)是,如果您在此更改後重新加載應用(yòng)程序,main()則不會(huì)重新執行,并且會(huì)使用(yòng)未修改的實例MyApp作(zuò)爲新構建的widget樹的根,熱重載後結果沒有變化。

限制

您可能(néng)還會(huì)遇到(dào)極少數情況下(xià)根本不支持熱重載的情況。這(zhè)些(xiē)包括:

枚舉類型更改爲常規類或常規類更改爲枚舉類型。例如,如果您更改:

enum Color {

red,

green,

blue

}

改爲:

class Color {

Color(this.i, this.j);

final Int i;

final Int j;

}

泛型類型聲明(míng)被修改。例如,如果您更改:

class A {

T i;

}

改爲:

class A {

T i;

V v;

}

在這(zhè)些(xiē)情況下(xià),熱重載會(huì)生成診斷消息,并會(huì)在未提交任何更改的情況下(xià)失敗。

網站(zhàn)建設開(kāi)發|APP設計(jì)開(kāi)發|小(xiǎo)程序建設開(kāi)發
下(xià)一篇:Flutter 測試應用(yòng)
上(shàng)一篇:Flutter 使用(yòng) Flutter IDE