Dart學習基礎之第二篇

Mixin


此圖可以簡單的描述一下類的繼承

備注:子類沒有重寫超類A方法的前提下,如果2個或多個超類擁有相同簽名的A方法,那么子類會以繼承的最后一個超類中的A方法為準。

如果子類自己重寫了A方法則以本身的A方法為準。


泛型-泛型函數

main() {

? K addCache<K, V>(K key, V value) {

? ? K temp = key;

? ? print('${key}: ${value}');

? ? return temp;

? }

? var key = addCache('dongnao', 'damon');

? print(key);

}

備注:Dart1.21開始可以使用泛型函數。

泛型函數可以在以下幾個地方使用類型參數:

? ? ? ? <1>? ? 函數的返回值類型。

? ? ? ? <2>? ? 參數的類型。

? ? ? ? <3>? ? 局部變量的類型。


泛型-構造函數泛型

main() {

? var p = Phone<String>('123456');

? print(p.mobileNumber);

}

class Phone<T> {

? final T mobileNumber;

? Phone(this.mobileNumber);

}

備注:Dart1.21開始可以使用泛型函數。

泛型函數可以在以下幾個地方使用類型參數:

? ? ? ? <1>? ? 函數的返回值類型。

? ? ? ? <2>? ? 參數的類型。

? ? ? ? <3>? ? 局部變量的類型。


泛型-泛型限制

main() {

? var footMassage = FootMassage();

? var m = Massage<FootMassage>(footMassage);

? m.massage.doMassage();

}

class Massage<T extends FootMassage > {

? final T massage;

? Massage(this.massage);

}

class FootMassage {

? void doMassage() {

? ? print('腳底按摩');

? }

}

備注:實現泛型類型時,您可能希望限制其參數的類型,可以在<>里面使用extends。


泛型-與java區別

Java中的泛型信息是編譯時的,泛型信息在運行時是不存在的

Dart的泛型類型是固化的,在運行時也有可以判斷的具體類型

var names = List<String>();

print(names is List<String>);//true

print(names.runtimeType); // List<String>

備注:在Java中,可以測試對象是否為List,但無法測試它是否是List<String>。

庫-使用核心庫

使用import關鍵字來載入庫:

import "dart:math";

void main() {

? print(sqrt(4));//開平方 2.0

}

備注:import 后的必須參數為庫 的 URI。(Uniform?Resource?Identifier統一資源標識符)

對于內置的庫,URI 使用特殊的 dart: scheme。

對于其他的庫,你可以使用文件系統路徑或者 package: scheme。


庫-載入第三方庫

1.編寫pubspec.yaml:
dependencies:

? flutter:

? ? sdk: flutter

? cupertino_icons: ^0.1.0

? dio: ^2.1.0

2.調用

import "package:dio/dio.dart";

void main() {

? getHttp();

}

void getHttp() async {

? try {

? ? Response response = await Dio().get("https://www.baidu.com");

? ? print(response);

? } catch (e) {

? ? print(e);

? }

}

庫-指定庫前綴

如果兩個庫有沖突的標識符,可以為其中一個或兩個庫都指定前綴:

import 'MyLib1.dart' as lib1;

import 'MyLib2.dart' as lib2;

void main() {

? var myLib = lib1.MyLib();

? var myLib2 = lib2.MyLib();

}

庫-選擇性載入

show-只載入庫的某些部分

hide-篩選掉庫的某些部分

import 'Mylib1.dart' as lib1 show Test;

import 'Mylib2.dart' as lib2 hide Test;

var test = lib1.Test();

var lib = lib2.MyLib();

備注:果只使用庫的一部分功能,則可以選擇需要導入的 內容。

庫-延遲載入

使用deferred as導入

使用標識符調用loadLibrary()加載庫

import 'MyLib1.dart' deferred as lazyLib;

void main() {

? lazyLoad();

}

lazyLoad() async {

? await lazyLib.loadLibrary();

? var t = lazyLib.Test();

? t.test();

}

備注:使用 await 關鍵字暫停代碼執行一直到庫加載完成。

可提高程序啟動速度。

用在不常使用的功能。

用在載入時間過長的包。

執行 A/B 測試,例如 嘗試各種算法的 不同實現。

庫-自定義庫

1.//mylib/mylib.dart

library mylib;

part 'util.dart';

part 'tool.dart';

void printMyLib() => print('mylib');


2.//mylib/tool.dart

part of mylib;

void printTool() => print('tool');

3.import 'mylib/mylib.dart';

void main() {

? printMyLib();

? printUtil();

? printTool();

}

備注:part 可以把一個庫分開到多個 Dart 文件中。

或者我們想讓某一些庫共享它們的私有對象的時候,可以需要使用part。

import不會完全共享作用域,而part之間是完全共享的。如果說在A庫中import了B庫,B庫import了C庫,A庫是沒有辦法直接使用C庫的對象的。而B,C若是A的part,那么三者共享所有對象。并且包含所有導入。


異步-async和await

void main(){

? getName1();

? getName2();

? getName3();

}

Future getName1() async {

? await getStr1();

? await getStr2();

? print('getName1’);

}

getStr1() {

? print('getStr1’);

}

getStr2() {

? print('getStr2’);

}

getName2() {

? print('getName2’);

}

getName3() {

? print('getName3’);

}

備注:await關鍵字必須在async函數內部使用

await表達式可以使用多次


異步-then,catchError,whenComplete

void main() {

? new Future(() => futureTask())//異步任務的函數

? ? ? .then((m) => "result:$m")//任務執行完后的子任務

? ? ? .then((m) => m.length) //其中m為上個任務執行完后的返回的結果

? ? ? .then((m) => printLength(m))

? .catchError(print)

? ? ? .whenComplete(() => whenTaskCompelete());//所有任務完成后的回調函數

}

備注:

如果需要監聽“完畢”這個狀態,那么用whenComplete,需要監聽“成功”這個狀態,用then,需要監聽“失敗”這個狀態,用catchError。

如果重寫了test方法,test返回true就可以在catchError的onError方法里捕獲到異常,如果test返回false,就把該異常繼續拋出而不會在catchError方法里被捕獲,如果不寫test默認實現一個返回true的test方法


異步-Event-Looper


備注:一個消息循環的職責就是不斷從消息隊列中取出消息并處理他們直到消息隊列為空。

消息隊列中的消息可能來自用戶輸入,文件I/O消息,定時器等。例如上圖的消息隊列就包含了定時器消息和用戶輸入消息。

Dart中的Main Isolate只有一個Event Looper,但是存在兩個Event Queue: Event Queue以及Microtask Queue。

異步-Event Queue和Microtask Queue


備注:優先全部執行完Microtask Queue中的Event。

直到Microtask Queue為空時,才會執行Event Queue中的Event。

當Event Looper正在處理Microtask Queue中的Event時候,Event Queue中的Event就停止了處理了,此時App不能繪制任何圖形,不能處理任何鼠標點擊,不能處理文件IO等等。

繪制圖形,處理鼠標點擊,處理文件IO等都是在Event Queue里完成的。

異步-任務調度

使用Future類,可以將任務加入到Event Queue的隊尾

使用scheduleMicrotask函數,將任務加入到Microtask Queue隊尾


異步-new Future()

void main(){

? testFuture();

}

void testFuture() {

? Future f = new Future(() => print('f1'));

? Future f1 = new Future(() => null);

? //Future f1 = new Future.delayed(Duration(seconds: 1) ,() => null);

? Future f2 = new Future(() => null);

? Future f3 = new Future(() => null);

? f3.then((_) => print('f2'));

? f2.then((_) {

? ? print('f3');

? ? new Future(() => print('f4'));

? ? f1.then((_) {

? ? ? print('f5');

? ? });

? });

? f1.then((m) {

? ? print('f6');

? });

? print('f7');

}

備注:使用new Future將任務加入event隊列。

Future中的then并沒有創建新的Event丟到Event Queue中,而只是一個普通的Function Call,在FutureTask執行完后,立即開始執行。

如果在then()調用之前Future就已經執行完畢了,那么任務會被加入到microtask隊列中,并且該任務會執行then()中注冊的回調函數。

使用Future.value構造函數的時候,就會上一條一樣,創建Task丟到microtask Queue中執行then傳入的函數。

Future.sync構造函數執行了它傳入的函數之后,也會立即創建Task丟到microtask Queue中執行。

當任務需要延遲執行時,可以使用new Future.delay()來將任務延遲執行。


異步-scheduleMicrotask()

import 'dart:async';

void main(){

? testFuture();

}

void testScheduleMicrotask(){

? scheduleMicrotask(() => print('s1'));

? new Future.delayed(new Duration(seconds: 1), () => print('s2'));

? new Future(() => print('s3')).then((_) {

? ? print('s4');

? ? scheduleMicrotask(() => print('s5'));

? }).then((_) => print('s6'));

? new Future(() => print('s7'));

? scheduleMicrotask(() => print('s8'));

? print('s9');

}

備注:如果可以,盡量將任務放入event隊列中。

使用Future的then方法或whenComplete方法來指定任務順序。

為了保持你app的可響應性,盡量不要將大計算量的任務放入這兩個隊列。

大計算量的任務放入額外的isolate中。

生成器-同步生成器

Main(){

? var it = getSyncGenerator(5).iterator;

? while (it.moveNext()) {

? ? print(it.current);

? }

}

Iterable<int> getSyncGenerator(int n) sync* {

? print('start');

? int k = 0;

? while (k < n) {

? ? yield k++;

? }

? print('end');

}

備注:使用sync*,返回的是Iterable對象。

yield會返回moveNext為true,并等待 moveNext 指令。

調用getSyncGenerator立即返回Iterable對象。

調用moveNext方法時getSyncGenerator才開始執行。

生成器-異步生成器

Main(){

//getAsyncGenerator(5).listen((value) => print(value));

? StreamSubscription subscription = getAsyncNumIterator(5).listen(null);

? subscription.onData((value) {

? ? print(value);

? ? if(value>=2){

? ? ? subscription.pause();

? ? }

? });

}

Stream<int> getAsyncGenerator(int n) async* {

? print('start');

? int k = 0;

? while (k < n) {

yield k++;

? }

? print('end');

}

備注:使用async*,返回的是Stream對象。

yield不用暫停,數據以流的方式一次性推送,通過StreamSubscription進行控制。

調用getAsyncGenerator立即返回Stream,只有執行了listen,函數才會開始執行。

listen返回一個StreamSubscription 對象進行流監聽控制。

可以使用StreamSubscription對象對數據流進行控制。

生成器-遞歸生成器

Main(){

? var it = getSyncRecursiveGenerator(5).iterator;

? while (it.moveNext()) {

? ? print(it.current);

? }

}

Iterable<int> getSyncRecursiveGenerator(int n) sync* {

? if (n > 0) {

? ? yield n;

? ? yield* getSyncNumDownFrom(n - 1);

? }

}

備注:yield* 以指針的方式傳遞遞歸對象,而不是整個同步對象。

隔離-Isolates

所有Dart代碼都在隔離區內運行,而不是線程。每個隔離區都有自己的內存堆,確保不會從任何其他隔離區訪問隔離區的狀態。

備注:Dart沒有共享內存的并發,沒有競爭的可能性所以不需要鎖,也就不用擔心死鎖的問題。

isolate之間沒有共享內存,所以他們之間的通信唯一方式只能是通過Port進行,而且Dart中的消息傳遞總是異步的。

isolate神似Thread,但實際上兩者有本質的區別。操作系統內的線程之間是可以有共享內存的而isolate沒有,這是最為關鍵的區別。

元數據(注解)-@deprecated

main() {

? dynamic tv = new Television();

? tv.activate();

? tv.turnOn();

}

class Television {

? @deprecated

? void activate() {

? ? turnOn();

? }

? void turnOn() {

? ? print('Television turn on!');

? }

}

備注:所有的 Dart 代碼都可以使用: @deprecated 和 @override。

元數據(注解)-自定義


備注:在java中,如果自定義一個注解,需要添加 @Target 作用域注解,@Retention 注解類型注解,添加 @interface,然后定義注解參數。

構造方法定義為編譯時常量

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,431評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,637評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,555評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,900評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,629評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,976評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,976評論 3 448
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,139評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,686評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,411評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,641評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,129評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,820評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,233評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,567評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,362評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,604評論 2 380

推薦閱讀更多精彩內容