通過dart語言(一)的學習,相信大家已經(jīng)可以很熟練的寫出完整的應用程序了玩敏,但是想要寫出更優(yōu)秀锤悄、更完美的dart語言框架,還需要更深入的理解dart語言的一些特點驼侠。
接下來,我將帶領大家一起更深入的學習dart語言谆吴。
目錄
泛型
使用<...> 的方式來定義泛型泪电。
為什么使用泛型?
- 雖然Dart 語言中類型是可選的纪铺,但是明確的指明使用的是泛型相速,會讓代碼更好理解。
var names = new List<String>();
names.addAll(['xiaojian', 'lili', 'jim']);
- 使用泛型讓代碼更簡潔
abstract class IntCache {
int getByKey(String key);
setByKey(String key, int value);
}
abstract class StringCache {
String getByKey(String key);
setByKey(String key, String value);
}
上面兩個類可以優(yōu)化為:
abstract class Cache<T> {
T getByKey(String key);
setByKey(String key, T value);
}
集合類型
泛型用于List 鲜锚、Set突诬、 Map 類型參數(shù)化
var names = <String>['Seth', 'Kathy', 'Lars'];
var pages = <String, String>{
'index.html': 'Homepage',
'robots.txt': 'Hints for web robots',
'humans.txt': 'We are people, not machines'
};
構造函數(shù)中參數(shù)化類型
var names = new List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
var nameSet = new Set<String>.from(names);
var views = new Map<int, View>();
泛型集合及它們所包含的類型
var names = new List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
print(names is List<String>); // true
庫和可見性
使用import 和 library 指令可以方便的創(chuàng)建一個模塊或分享代碼。一個Dart 庫不僅能夠提供相應的API芜繁,還可以包含一些以_開頭的私有變量僅在庫內部可見旺隙。
每一個Dart 應用都是一個庫,即使它沒有使用library指令骏令。庫可以方便是使用各種類型的包蔬捷。
使用庫
使用import指定怎樣的命名空間,從一個庫引用另一個庫。
import唯一要求的參數(shù)是指定庫的URI周拐。
- dart內置庫铡俐,URI組合dart:
- 其他庫,使用文件路徑或package:組合妥粟,package:組合式通過包管理工具提供的审丘。
import 'package:flutter/material.dart';
import 'Home.dart';
庫的前綴
如果導入的庫擁有相互沖突的名字,使用as為其中一個或幾個指定不一樣的前綴勾给。
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
Element element1 = new Element(); // Uses Element from lib1.
lib2.Element element2 = new lib2.Element(); // Uses Element from lib2.
導入庫的一部分
如果只需要使用庫的一部分內容滩报,使用show或hide有選擇的導入。
// 僅導入foo.
import 'package:lib1/lib1.dart' show foo;
// 除了foo都導入
import 'package:lib2/lib2.dart' hide foo;
延遲加載
延遲加載播急,也叫懶加載脓钾,允許應用程序按需加載庫。使用延遲加載的場景:
- 減少程序初始化啟動時間桩警。
- 執(zhí)行A/B測試——嘗試替換一個算法的實現(xiàn)可训。
- 加載很少用的功能,比如可選的屏幕和對話框生真。
要延遲加載一個庫沉噩,首先必須使用deferred as導入它捺宗,當需要使用庫的時候柱蟀,使用庫名調用loadLibrary()。
import 'package:deferred/hello.dart' deferred as hello;
greet() async {
// 使用await關鍵字暫停執(zhí)行蚜厉,直到庫加載
await hello.loadLibrary();
hello.printGreeting();
}
異步(async和await)
使用async函數(shù)和await表達式實現(xiàn)異步操作长已。
當需要使用一個從Future返回的值時,有兩個選擇:
- 使用async和await昼牛。
- 使用Future API术瓮。
當需要從一個Stream獲取值時,有兩個選擇:
- 使用async和異步的循環(huán)(await for)贰健。
- 使用Stream API胞四。
代碼使用了async和await就是異步的,雖然看起來像同步代碼伶椿。
static postData(String path, Map<String, String> params,Function successCallBack) async {
var httpClient = HttpClient();
var uri = new Uri.https(
HOST, path, _createPostData(params));
var request = await httpClient.postUrl(uri);
var response = await request.close();
if (response.statusCode == HttpStatus.OK) {
var json = await response.transform(UTF8.decoder).join();
var data = JSON.decode(json);
print("data=====" + data.toString() );
if(successCallBack!=null){
successCallBack(data['data']);
}
} else {
print("data=====error");
}
}
聲明異步函數(shù)
異步函數(shù)是一個被async標記的函數(shù)辜伟。
雖然異步的函數(shù)中可能執(zhí)行耗時的操作,但是函數(shù)本身在調用后將會立即返回脊另,即使函數(shù)體一條語句也沒執(zhí)行导狡。
給函數(shù)添加async關鍵字將使函數(shù)返回一個Future類型
checkVersion() async {
// ...
}
lookUpVersion() async => /* ... */;
案例
getData(String path, Map<String, String> params) async {
var httpClient = HttpClient();
var uri = new Uri.https(
HOST, path, _createPostData(params));
var request = await httpClient.postUrl(uri);
var response = await request.close();
return await response.transform(UTF8.decoder).join();
}
調用函數(shù)想獲得其結果:
void main(){
String a = getData("/bbs/list",map);
print(a);
}
運行后程序報錯:
Failed to load "/Users/wangxiaojian/Documents/androidCode/flutter_rong_app/test/widget_test.dart": type 'Future<dynamic>' is not a subtype of type 'String'
test/widget_test.dart 55:14 main
===== asynchronous gap ===========================
package:test serializeSuite
/var/folders/j7/0w0w7vgd6s5f_gv67_jfzgjr0000gn/T/dart_test_listenerqkAJjf/listener.dart 19:27 main
因為data是String類型,而函數(shù)getData()是一個異步操作函數(shù)偎痛,其返回值是一個await延遲執(zhí)行的結果旱捧。在Dart中,有await標記的運算踩麦,其結果值都是一個Future對象枚赡,F(xiàn)uture不是String類型氓癌,所以就報錯了。
那如果這樣的話标锄,我們就沒法獲取到延遲執(zhí)行的結果了顽铸?當然可以,Dart規(guī)定有async標記的函數(shù)料皇,只能由await來調用谓松,比如這樣:
void main() async{
// await 必須在有async標記的函數(shù)中運行
String a = await getData("/bbs/list",map);
print(a);
}
上面這種方法一般用于調用封裝好的異步接口,比如getData()被封裝到了其他dart文件践剂,通過使用async函數(shù)對其調取使用
- await關鍵字必須在async函數(shù)內部使用
- 調用async函數(shù)必須使用await關鍵字
PS:await關鍵字真的很形象鬼譬,等一等的意思,就是說逊脯,既然你運行的時候都要等一等优质,那我調用的時候也等一等吧
為什么要用Future?
在定義Flutter函數(shù)時军洼,還可以指定其運行結果返回值的類型巩螃,以提高代碼的可讀性:
Future<String> getData(String path, Map<String, String> params) async {
var httpClient = HttpClient();
var uri = new Uri.https(
HOST, path, _createPostData(params));
var request = await httpClient.postUrl(uri);
var response = await request.close();
return await response.transform(UTF8.decoder).join();
}
Future最主要的功能就是提供了鏈式調用,熟悉ES6語法的小伙伴都應該很熟悉匕争,鏈式調用解決兩大問題:明確代碼執(zhí)行的依賴關系和實現(xiàn)異常捕獲避乏。
看下面案例:
String _name = "";
void _setName(String name) async{
_name = name;
}
void _getName() async{
await _setName("wangxiaojian");
print(_name);
}
void main() async{
await _getName();
}
如果要想先執(zhí)行_getName再執(zhí)行_setName,必須在_getName中await _setName();_setName的代碼與_getName耦合甘桑,將來如果_getName廢掉或者改動拍皮,_setName中還需要經(jīng)過修改以適配變更。
為了解決此問題跑杭,F(xiàn)uture提供了一套非常簡潔的解決方案,而async和await無法企及的铆帽,因此掌握Future還是很有必要滴:
String _name = "";
_setName() {
_name = "wangxiaojian";
}
_getName() {
print(_name);
}
void main() {
new Future(_setName()).then(_getName());
}
可調用類
Dart 語言中為了能夠讓類像函數(shù)一樣能夠被調用,可以實現(xiàn)call()方法德谅。
class ClassFunction {
call(String a, String b, String c) => '$a $b $c!';
}
main() {
var cf = new ClassFunction();
var out = cf("wangxiaojian","is","talent");
print('$out');
print(cf.runtimeType);
print(out.runtimeType);
print(cf is Function);
}
運行結果:
wangxiaojian is talent!
ClassFunction
String
false
類型定義
typedef關鍵字爹橱,用來聲明一種類型,當一個函數(shù)類型分配給一個變量時窄做,保留類型信息愧驱。
// 聲明一種 Compare類型
typedef int Compare(int a, int b);
int sort(int a, int b) => a - b;
main() {
print(sort is Compare);
}
運行結果:
true
元數(shù)據(jù)
元數(shù)據(jù)是以@開始的修飾符。在@ 后面接著編譯時的常量或調用一個常量構造函數(shù)浸策。
所有dart代碼中可用的三個注解:
- @deprecated 被棄用的
- @override 重載
- @proxy 代理
定義自己的元數(shù)據(jù)
通過library來定義一個庫冯键,在庫中定義一個相同名字的class,然后在類中定義const 構造方法庸汗。
// 定義
library todo;
class todo {
final String who;
final String what;
const todo(this.who, this.what);
}
// 使用
import 'todo.dart';
@todo('seth', 'make this do something')
void doSomething() {
print('do something');
}
元數(shù)據(jù)可以修飾library(庫), class(類), typedef(類型定義), type parameter(類型參數(shù)), constructor(構造函數(shù)), factory(工廠函數(shù)), function(函數(shù)), field(作用域), parameter(參數(shù)), 或者 variable declaration(變量聲明)惫确。
可以使用reflection反射,在運行時檢查元數(shù)據(jù)。