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,然后定義注解參數。
構造方法定義為編譯時常量