前言
關(guān)于請求網(wǎng)絡(luò)數(shù)據(jù),是每個應(yīng)用程序中最頻繁的場景挤悉。在iOS開發(fā)中,我們通常使用NSURLSession+NSURLRequest
或者第三方框架(AFNetworking
,Alamfire
等)來完成網(wǎng)絡(luò)數(shù)據(jù)請求并渲染界面。而在Flutter中又是怎么玩兒吶射亏?接下來我們一起看一下命斧。
開始前先給大家介紹2個網(wǎng)站:
-
pub.dev :Dart相關(guān)的擴展
pakage
田晚,在這里都能找到。(Find and use packages to build Dart and Flutter app. 這個解釋比較到位)国葬。今天我們網(wǎng)絡(luò)請求就用到了http: ^0.12.1
(其實這個網(wǎng)站類似于iOS的下的cocopods)贤徒。 - RAP2 :基于Mock的可視化工具(熟系mock.js會比較熟悉這個芹壕,web端開發(fā)經(jīng)常用到),可以創(chuàng)建接口和返回數(shù)據(jù)。這個的好處就是在后臺還沒有給提供相應(yīng)接口的時候我們可以通過這個方式來模擬請求完成我們的業(yè)務(wù)開發(fā)接奈。
Flutter中的序列化與反序列化
這里我們簡單的用一下Flutter中的json
,主要方法就2個:
json.encode()
: json字符串轉(zhuǎn)為Map對象
json.decode()
:Map對象轉(zhuǎn)為json字符串
這里并沒有直接轉(zhuǎn)為Model的方法踢涌,我們還需要稍微的做一些處理,先創(chuàng)建一個Model類
class ChatUser {
final String iconUrl;
final String userName;
final String useDes;
ChatUser({this.iconUrl, this.userName, this.useDes});
factory ChatUser.fromJson(Map json) { //這里是一個Map=>model的方法
return ChatUser(
iconUrl: json['icon_url'],
userName: json['user_name'],
useDes: json['use_des'],
);
}
}
我們通過一個fromJson(Map json)
的方法完成map=>model的轉(zhuǎn)換序宦。
簡單使用一下:
//在Flutter簡單的 json <=> model
void jsonModel() {
//測試數(shù)據(jù)
final testMap = {
'iconUrl': 'http://zezefamily/hello_flutter',
'userName': 'zezefamily',
'useDes': '澤澤是個好人',
};
//Map(NSDictionary) 轉(zhuǎn) json
final jsonStr = json.encode(testMap);
print(jsonStr);
//json 轉(zhuǎn) Map
final jsonMap = json.decode(jsonStr);
print(jsonMap['userName']);
//Map 轉(zhuǎn) Model
ChatUser model = ChatUser.fromJson(jsonMap);
print(model.userName);
}
基礎(chǔ)應(yīng)用還是比較容易的睁壁。但是涉及到復(fù)雜的model 比如model中嵌套model就無法完成了。更多好用的序列化與反序列化話的package還是很多的互捌,比如json_serializable包潘明。可以去我上面提到的網(wǎng)址里面找到秕噪。
開始造
引入http: ^0.12.1
到pubspec.yaml
文件钳降,并執(zhí)行Packages get
(這個操作可以通過終端命令執(zhí)行,也可以直接點擊pubspec.yaml
文件頂部的Packages get
)腌巾。這個Packages get
就類似于iOS在使用pods管理庫時的pod install
遂填。
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.3
http: ^0.12.1 //新引入的http
使用http
import 'package:http/http.dart' as Http;
//as xxx 相當于定義了一個類名,方法可以通過這個類名調(diào)起
發(fā)起一個網(wǎng)絡(luò)請求
// func: 請求網(wǎng)絡(luò)數(shù)據(jù)
Future<List<ChatUser>> getData() async {
//發(fā)起get請求
final response =
await Http.get('http://rap2.taobao.org:38080/app/mock/data/1624211');
if (response.statusCode == 200) {
//獲取響應(yīng)數(shù)據(jù)并轉(zhuǎn)為Map
final respBody = json.decode(response.body);
List<ChatUser> list = respBody['user_list'].map<ChatUser>((item) {
return ChatUser.fromJson(item);
}).toList();
return list;
} else {
throw Exception('errorCode:${response.statusCode}');
}
}
這里可以看到這么幾個東西:Future
,async
,await
:
-
Future
:字面意思未來。也就是說未來發(fā)送的事情誰也說不準??澈蝙,雖然你調(diào)用了getData()
吓坚,想要的結(jié)果是一個List包裝好的數(shù)據(jù),但是說不準哪里出問題碉克,我就無法滿足你的需求凌唬,無法滿足你!B┞蟆客税!所以通過返回Future
來給你一些額外的機會,去做一些處理撕贞,想辦法滿足你8堋!捏膨! -
async
:標記該方法為異步執(zhí)行秧均,在子線程完成; -
await
:標記之后号涯,必須等該方法執(zhí)行完成后目胡,下面的方法才能繼續(xù)執(zhí)行;這個跟iOS下GCD
的dispatch_semaphore_signal()
和dispatch_semaphore_wait()
一樣链快。
調(diào)用getData()
:
@override
void initState() {
// TODO: implement initState
super.initState();
print('initState執(zhí)行了');
//發(fā)起數(shù)據(jù)
getData()
.then((List<ChatUser> datas) {
print(datas);
setState(() {
_datas = datas;
});
})
.catchError((error) {
print('錯誤信息:$error');
})
.whenComplete(() {
print('本次請求完成');
})
.timeout(Duration(seconds: 6))
.catchError((timeoutError) {
print('請求超時誉己;$timeoutError');
});
}
這里就看到Future
的價值了;他可以通過.then(()=>{})
拿到返回的數(shù)據(jù)域蜗,如果有異常會執(zhí)行到.catchError(()=>)
,當本次請求完成后會執(zhí)行.whenComplete(()=>)
,可以通過.timeout(Duration(seconds:6))
設(shè)置超時時間,超時處理會來到.catchError(()=>{})
巨双。 這個方式看似非常像iOS下的block
, 其實在java
,swift
,javascript
等語法中噪猾,這種鏈式調(diào)用的語法非常常見,它確實看的非常的清晰易讀易懂筑累。
刷新頁面:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('待上課程'),
),
body: Container(
child: _datas.length == 0
? Center(
child: Text('數(shù)據(jù)加載中...'),
)
: ListView.builder(
itemCount: _datas.length,
itemBuilder: (BuildContext context,int index){
return ListTile(
title: Text(_datas[index].userName),
subtitle: Text(_datas[index].useDes),
leading: CircleAvatar(
backgroundImage: NetworkImage(_datas[index].iconUrl),
),
);
},
),
));
}
}
這里做了一個簡單的邏輯判斷袱蜡,當_datas.length == 0
時,顯示一個Text()
,否則顯示ListView.builder
, 這里看到了一些新的部件ListTitle()
和CircleAvatar()
-
ListTitle()
:理解為一個Cell,一個帶有title
,subtitle
,leading
(左邊部分,這里可以是任意widget)的cell慢宗,類似于iOS下的UITableViewCell.UITableViewCellStyleSubtitle
風格坪蚁; -
CircleAvatar()
:就是字面意思,圓形頭像部件婆廊,可以配置一個backgroundImage
;
來看下最終效果圖:
總結(jié)
關(guān)于http: ^0.12.1
迅细,本文中就是簡單的應(yīng)用了一個GET
的請求,其它的請求方式比如POST
,如何帶參數(shù)淘邻,如何配置請求頭等這里就不贅述了。http
是dart下最基礎(chǔ)網(wǎng)絡(luò)請求方式湘换,其實有很多基于http
的優(yōu)秀package包宾舅,還有很多序列化/反序列化的package,大家可以在上面我提供的網(wǎng)站中找到。