Flutter & Dart 基礎(chǔ)

以下主要是學(xué)習(xí)極客時間 Flutter 專欄相關(guān)學(xué)習(xí)記錄胁镐。

Dart 基礎(chǔ)

Online Dart iDE

核心特性

JIT & AOT

Dart 同時支持 JITAOT 兩種編譯方式蜜自。

  • JIT:Just In Time碌宴,運行時即時編譯,開發(fā)效率高。可動態(tài)下發(fā)和執(zhí)行代碼崭庸,運行速度和性能受到影響。Flutter 的熱重載基礎(chǔ)這一特性谊囚。( 開發(fā) Debug 模式使用)

    image.png
將 `Dart` 編譯生成中間代碼 `Script Snapshot`怕享,由   `Dart VM` 解釋執(zhí)行。 
  • AOT:Ahead Of Time镰踏,需要預(yù)先編譯函筋,開發(fā)效率低。但運行速度快余境,性能表現(xiàn)好驻呐。(發(fā)布 Release 模式使用)

    image.png

    編譯生成設(shè)備對應(yīng)的二進(jìn)制。

內(nèi)存分配與垃圾回收

內(nèi)存分配

Dart VM 的內(nèi)存分配芳来,只需要在堆上移動指針含末,內(nèi)存增長是線性的。

Dart 通過 Isolate 實現(xiàn)并發(fā)即舌,但并不共享內(nèi)存佣盒,可以實現(xiàn)無鎖快速分配。

垃圾回收

垃圾回收顽聂,采用多生代算法肥惭。

  1. 調(diào)度器

    檢測到程序處于空閑狀態(tài)盯仪,沒有用戶交互時,進(jìn)行回收蜜葱,減少 GC 對性能的影響全景。

  2. 年輕代

    新生代空間收集器,清除壽命較短的短暫對象牵囤。

    由于對象被分配在連續(xù)空間中爸黄,在創(chuàng)建對象時,他們被分配到可用空間揭鳞,直到分配的內(nèi)存填充完畢炕贵。

    分配給新對象的連續(xù)空間由兩部分組成,任何時候只使用一半野崇,分為活動空間和非活動空間称开。新生成的對象在活動區(qū)間,一旦填充完畢乓梨,不可回收對象從活動空間復(fù)制到非活動空間鳖轰。活動空間進(jìn)行清理扶镀,非活動空間轉(zhuǎn)變?yōu)榛顒涌臻g脆霎。

    過程如下圖所示:

image.png
  1. 老年代

    并行標(biāo)記掃描收集器,清除生命周期比較長的對象狈惫。采用標(biāo)記整理的方法回收對象。

    a. 遍歷對象圖鹦马,標(biāo)記仍在使用的對象胧谈。

    b. 掃描,回收未被標(biāo)記的對象荸频,清除標(biāo)記菱肖。

    如下圖所示:

image.png

單線程模型

Dart 是單線程模型,通過 Event Loop 實現(xiàn)異步旭从。

image.png
  • 微任務(wù)隊列:短時間會完成的任務(wù)稳强,比事件隊列優(yōu)先級更高,當(dāng)其不為空和悦,會一直占著事件循環(huán)退疫。一般情況不會用到。目前只有 Flutter 內(nèi)部用到鸽素,如手勢識別褒繁,滾動視圖等高優(yōu)先級操作。
  • 事件隊列:用得較多馍忽,如定時器棒坏、IO 等燕差。
Future

使用 Future 將同步任務(wù)包裝成異步任務(wù),把函數(shù)體放到事件隊列中坝冕,立即返回徒探。后面代碼同步執(zhí)行,執(zhí)行完成后喂窟,從事件隊列中取出事件测暗,依次同步執(zhí)行函數(shù)體及后續(xù)的 then

Future(() => print('Running in Future 1'));//下一個事件循環(huán)輸出字符串

Future(() => print('Running in Future 2'))
  .then((_) => print('and then 1'))
  .then((_) => print('and then 2'));//上一個事件循環(huán)結(jié)束后谎替,連續(xù)輸出三段字符串
  
Future(() => print('Running in Future 3'));

print('hello');

結(jié)果:

hello
Running in Future 1
Running in Future 2
and then 1
and then 2
Running in Future 3

若要同步等待 Future 中完成偷溺,使用 awaitawait钱贯、async 用法 與 js 中的類似挫掏。

并發(fā)

Dart 中沒有線程,并發(fā)通過 Isolate 實現(xiàn)秩命,并且 Isolate 之間不共享內(nèi)存尉共。每個Isolate 有自己獨立的堆棧,Event LoopQueue弃锐。它們之間通過消息機制(發(fā)送管道 sendPort)進(jìn)行通信袄友。

比如,主 Isolate 向并發(fā)Isolate傳入自己的發(fā)送管道霹菊,并監(jiān)聽管道消息剧蚣。這樣,并發(fā) Isolate 就可以通過該管道發(fā)送消息旋廷。


Isolate isolate;

start() async {
  ReceivePort receivePort= ReceivePort();//創(chuàng)建管道
  
  //創(chuàng)建并發(fā)Isolate鸠按,并傳入發(fā)送管道
  isolate = await Isolate.spawn(getMsg, receivePort.sendPort);
  
  //監(jiān)聽管道消息
  receivePort.listen((data) {
    print('Data:$data');
    receivePort.close();//關(guān)閉管道
    isolate?.kill(priority: Isolate.immediate);//殺死并發(fā)Isolate
    isolate = null;
  });
}

//并發(fā)Isolate往管道發(fā)送一個字符串
getMsg(sendPort) => sendPort.send("Hello");

基礎(chǔ)語法

變量與類型

  • 未初始化的變量值都為 null

  • 可自行指定類型饶碘,或由編譯器推導(dǎo)目尖。

    var:表示類型由編譯器判斷。

  • 所有類型都是對象類型扎运,繼承自 Object瑟曲。

  • 基本數(shù)據(jù)類型:num、bool豪治、String洞拨、List、Map鬼吵。

  • num:64 位整形 Int扣甲,64 位浮點型 Double

  • bool:true、false琉挖。需要顯式進(jìn)行比較启泣。if (a != 0) {}

  • String:單雙引號都可以,多行用三個單引號或雙引號示辈。

List寥茫、Map

JavaSwift 類似矾麻。

List:

// 自動推導(dǎo)元素類型為 `String`
var arr1 = ["Tom", "Andy", "Jack"];

// 顯式聲明
var arr1 = <String>['Tom', 'Andy', 'Jack'];

Map:

// 自動推導(dǎo)類型為 `Map<String: String>`
var map1 = {"name": "Tom", 'sex': 'male'};

// 顯式聲明
var map1 = <String, String>{'name': 'Tom','sex': 'male',};

推薦顯式聲明纱耻,可讀性好,當(dāng)添加不匹配類型時险耀,編譯器根據(jù)聲明類型做錯誤提示弄喘。

常量定義

const:在編譯期確定的值,適用于定義字面量甩牺。

const count = 3;

final:在運行期確定蘑志,一旦確定,不能修改贬派。

var x = 70; 
var y = 30;
final z = x / y;

函數(shù)

函數(shù)定義

bool isZero(int number) { 
    //判斷整數(shù)是否為0 
    return number == 0; 
}

若函數(shù)只有一行急但,可以使用箭頭函數(shù)來簡化函數(shù)定義。

bool isZero(int number) => number == 0;

參數(shù)

可選命名參數(shù)

給參數(shù)添加 {}搞乏,類似于 map波桩,調(diào)用時指定傳入哪些參數(shù),位置隨意请敦。

定義:

// 可選命名參數(shù)
void enable1Flags({bool bold, bool hidden}) => print("$bold , $hidden");

調(diào)用:

enable1Flags(bold: true, hidden: false); //true, false
enable1Flags(bold: true); //true, null
可選參數(shù)

給參數(shù)加上 []镐躲,即這些參數(shù)是可選的,可設(shè)置默認(rèn)值侍筛。

定義:

void enable4Flags(bool bold, [bool hidden = false]) => print("$bold ,$hidden");

調(diào)用:

enable4Flags(true); //true, false

定義與 Java 類似匀油,但沒有 public、protected勾笆、private 關(guān)鍵字,通過 _ 來區(qū)分是 private桥滨。private 的限制是庫訪問級別窝爪。

class Point { 
    num x, y; 
    static num factor = 0; 
    
    //語法糖,等同于在函數(shù)體內(nèi):this.x = x;this.y = y; 
    Point(this.x,this.y); 

    void printInfo() => print('($x, $y)'); 
    static void printZValue() => print('$factor');
}

var p = new Point(100,200); // new 關(guān)鍵字可以省略

p.printInfo(); // 輸出(100, 200);

Point.factor = 10;
Point.printZValue(); // 輸出10

為了使得實例化語義清晰化齐媒,支持命名構(gòu)造函數(shù)蒲每,類似指定構(gòu)造函數(shù)。

// 命名構(gòu)造函數(shù)
Point.bottom(num x) : this(x, 0);

// 實例化
var p = Point.bottom(100);

復(fù)用

繼承與接口實現(xiàn)喻括。

  • 繼承會自動獲取父類的成員變量和方法實現(xiàn)邀杏,子類可以根據(jù)需要覆寫構(gòu)造函數(shù)及父類方法;
  • 接口實現(xiàn),需要重新實現(xiàn)成員變量望蜡,以及方法的聲明和初始化唤崭,否則編譯器會報錯。
class Point { 
    num x = 0, y = 0; 
    void printInfo() => print('($x,$y)');
}
    
Vector extends Point{ 
    num z = 0; 
    @override 
    void printInfo() => print('($x,$y,$z)');
}

// Coordinate是對Point的接口實現(xiàn)
class Coordinate implements Point { 
    // 成員變量需要重新聲明 
    num x = 0, y = 0; 

    // 成員函數(shù)需要重新聲明實現(xiàn)
    void printInfo() => print('($x,$y)'); 
}
Mixin

Mixin脖律,即混入谢肾,為了解決多繼承帶來的問題。使用混入復(fù)用代碼小泉,并不是繼承關(guān)系 is a芦疏,類似組合 has a。通過這種方式可以調(diào)用混入類的變量和方法微姊,使用 with 關(guān)鍵字即可酸茴。

注意,如果混入的多個類中有同名的方法且被調(diào)用兢交,會以最后一個混入類為準(zhǔn)薪捍。

class Coordinate with Point {
}

var x = Coordinate();

// 調(diào)用 Point 類中的方法
x.printInfo();

運算符

  • ?.p?.printInfo()魁淳,若 p 為空飘诗,則不調(diào)用。類似于Swift 中的可選類型界逛。
  • ??=昆稿,a ??= value,若 anull息拜,則給 a 賦值 value溉潭。
  • ??a ?? b少欺,若 a 為空喳瓣,則取 b;否則取 a赞别。
自定義與復(fù)寫
class Vector { 
    num x, y; 
    Vector(this.x, this.y); 

    // 自定義 +
    Vector operator +(Vector v) => Vector(x + v.x, y + v.y); 

    // 覆寫 ==
    bool operator == (dynamic v) => x == v.x && y == v.y;
}

final x = Vector(3, 3);
final y = Vector(2, 2);
print(x == y);
print((x + y).x);

Flutter

跨平臺 UI 渲染框架畏陕,重寫了底層渲染邏輯。在 iOSAndroid 上, UI 層面表現(xiàn)高度一致仿滔。底層基于 Skia惠毁,C++ 編寫的強大的跨平臺圖形繪制引擎。

RN不同的是崎页,Fluter 是自己完成了組件的渲染鞠绰。
RN 是通過 JS 虛擬機作為橋梁調(diào)用到原生組件,最終生成的還是各端的原生組件飒焦,兩端會有差異性蜈膨。

Widget

widget:一種抽象的結(jié)構(gòu)化信息描述。

Flutter 中一切皆為 widget,比如應(yīng)用翁巍、視圖驴一、布局等。

Widget 渲染過程

涉及到三部分:Widget曙咽、Element蛔趴、RenderObject,其中 Element 連接 WidgetRenderObject例朱,分別持有孝情。

image.png
  • Widget:不可變,配置信息發(fā)生變化時洒嗤,會重建 Widget 樹箫荡,但它并不涉及到視圖的渲染,重建成本低渔隶。

  • Element:可變羔挡,可以看成 Widget 對應(yīng)的一種數(shù)據(jù)結(jié)構(gòu),一個實例化的對象间唉,是視圖配置信息到最終渲染的橋梁绞灼。將 Widget 的變化做了一層封裝,類似于 React 中的虛擬 DOM diff呈野,只將需要改動的部分同步給 RenderObject低矮,提高渲染效率。

  • RenderObject:真正的渲染對象被冒,負(fù)責(zé)布局與繪制军掂。之后的合成和渲染,交給 Skia昨悼。

深度優(yōu)先遍歷 Widget 樹 --> 生成對應(yīng)節(jié)點的 Element 對象 --> 生成 RenderObject蝗锥。

Widget變化時,持有該 WidgetElement 會設(shè)置為 dirty率触,觸發(fā) ElementRenderObject樹的更新终议。

與原生混編

Flutter 工程成為原生工程的子模塊,抽離 Fluter 工程葱蝗,按照不同平臺的構(gòu)建產(chǎn)物按照組件化的方式進(jìn)行管理痊剖。

其中原生工程對 Fluter 的依賴主要是:

  1. Flutter 的 Framework 和引擎庫。
  2. Flutter 工程垒玲,即我們自己實現(xiàn)的功能。

通過 flutter build 生成各自平臺的產(chǎn)物找颓。

Android:打成 aar 引入合愈,在 build.gradle 中添加依賴。
iOS:作為獨立 pod 引入,創(chuàng)建 podSpec佛析,在 podFile 中添加依賴益老。

調(diào)用原生能力

因為 Fluter 只接管了渲染層,所以原生系統(tǒng)能力無法提供寸莫,如藍(lán)牙捺萌、拍照、定位等等膘茎。

通過方法通道MethodChannel 方式桃纯,與原生進(jìn)行通信。類似網(wǎng)絡(luò)請求披坏,是請求 - 響應(yīng)式态坦。

image.png

Flutter 調(diào)用:

//聲明MethodChannel
const platform = MethodChannel('samples.chenhang/utils');

//異步等待方法通道的調(diào)用結(jié)果 
result = await platform.invokeMethod('openAppMarket');

原生處理:


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  //創(chuàng)建命名方法通道
  FlutterMethodChannel* channel = [FlutterMethodChannel methodChannelWithName:@"samples.chenhang/utils" binaryMessenger:(FlutterViewController *)self.window.rootViewController];
  
  //往方法通道注冊方法調(diào)用處理回調(diào)
  [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
    //方法名稱一致
    if ([@"openAppMarket" isEqualToString:call.method]) {
      //打開App Store
      [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"itms-apps://itunes.apple.com/xy/app/foo/id414478124"]];
      //返回方法處理結(jié)果
      result(@0);
    } else {
      //找不到被調(diào)用的方法
      result(FlutterMethodNotImplemented);
    }
  }];
  ...
}

同樣原生也可以調(diào)用 Flutter 方法,首先在 Flutter 方實現(xiàn)接口回調(diào)棒拂。
Native使用 [channel invokeMethod:@"xx" arguments:xx result:^(id _Nullable result) {}]; 進(jìn)行調(diào)用伞梯。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市帚屉,隨后出現(xiàn)的幾起案子谜诫,更是在濱河造成了極大的恐慌,老刑警劉巖攻旦,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件喻旷,死亡現(xiàn)場離奇詭異,居然都是意外死亡敬特,警方通過查閱死者的電腦和手機掰邢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來伟阔,“玉大人辣之,你說我怎么就攤上這事≈迓” “怎么了怀估?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長合搅。 經(jīng)常有香客問我多搀,道長,這世上最難降的妖魔是什么灾部? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任康铭,我火速辦了婚禮,結(jié)果婚禮上赌髓,老公的妹妹穿的比我還像新娘从藤。我一直安慰自己催跪,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布夷野。 她就那樣靜靜地躺著懊蒸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪悯搔。 梳的紋絲不亂的頭發(fā)上骑丸,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機與錄音妒貌,去河邊找鬼通危。 笑死,一個胖子當(dāng)著我的面吹牛苏揣,可吹牛的內(nèi)容都是我干的黄鳍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼平匈,長吁一口氣:“原來是場噩夢啊……” “哼框沟!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起增炭,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤忍燥,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后隙姿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體梅垄,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年输玷,在試婚紗的時候發(fā)現(xiàn)自己被綠了队丝。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡欲鹏,死狀恐怖机久,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情赔嚎,我是刑警寧澤膘盖,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站尤误,受9級特大地震影響侠畔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜损晤,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一软棺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧尤勋,春花似錦喘落、人聲如沸德崭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至锌奴,卻和暖如春兽狭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鹿蜀。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工箕慧, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人茴恰。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓倍奢,卻偏偏與公主長得像弟蚀,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容