iOS开发Flutter探索-请求网络数据(9)
前言
关于请求网络数据,是每个应用程序中最频繁的场景。在iOS开发中,我们通常使用NSURLSession+NSURLRequest
或者第三方框架(AFNetworking
,Alamfire
等)来完成网络数据请求并渲染界面。而在Flutter中又是怎么玩儿呐?接下来我们一起看一下。
开始前先给大家介绍2个网站:
-
pub.dev :Dart相关的扩展
pakage
,在这里都能找到。(Find and use packages to build Dart and Flutter app. 这个解释比较到位)。今天我们网络请求就用到了http: ^0.12.1
(其实这个网站类似于iOS的下的cocopods)。 - RAP2 :基于Mock的可视化工具(熟系mock.js会比较熟悉这个,web端开发经常用到),可以创建接口和返回数据。这个的好处就是在后台还没有给提供相应接口的时候我们可以通过这个方式来模拟请求完成我们的业务开发。
Flutter中的序列化与反序列化
这里我们简单的用一下Flutter中的json
,主要方法就2个:
json.encode()
: json字符串转为Map对象
json.decode()
:Map对象转为json字符串
这里并没有直接转为Model的方法,我们还需要稍微的做一些处理,先创建一个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的转换。
简单使用一下:
//在Flutter简单的 json <=> model
void jsonModel() {
//测试数据
final testMap = {
'iconUrl': 'http://zezefamily/hello_flutter',
'userName': 'zezefamily',
'useDes': '泽泽是个好人',
};
//Map(NSDictionary) 转 json
final jsonStr = json.encode(testMap);
print(jsonStr);
//json 转 Map
final jsonMap = json.decode(jsonStr);
print(jsonMap['userName']);
//Map 转 Model
ChatUser model = ChatUser.fromJson(jsonMap);
print(model.userName);
}
基础应用还是比较容易的。但是涉及到复杂的model 比如model中嵌套model就无法完成了。更多好用的序列化与反序列化话的package还是很多的,比如json_serializable包。可以去我上面提到的网址里面找到。
开始造
引入http: ^0.12.1
到pubspec.yaml
文件,并执行Packages get
(这个操作可以通过终端命令执行,也可以直接点击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 相当于定义了一个类名,方法可以通过这个类名调起
发起一个网络请求
// func: 请求网络数据
Future<List<ChatUser>> getData() async {
//发起get请求
final response =
await Http.get('http://rap2.taobao.org:38080/app/mock/data/1624211');
if (response.statusCode == 200) {
//获取响应数据并转为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
:字面意思未来。也就是说未来发送的事情谁也说不准😆,虽然你调用了getData()
,想要的结果是一个List包装好的数据,但是说不准哪里出问题,我就无法满足你的需求,无法满足你!!!所以通过返回Future
来给你一些额外的机会,去做一些处理,想办法满足你!!! -
async
:标记该方法为异步执行,在子线程完成; -
await
:标记之后,必须等该方法执行完成后,下面的方法才能继续执行;这个跟iOS下GCD
的dispatch_semaphore_signal()
和dispatch_semaphore_wait()
一样。
调用getData()
:
@override
void initState() {
// TODO: implement initState
super.initState();
print('initState执行了');
//发起数据
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(()=>{})
拿到返回的数据,如果有异常会执行到.catchError(()=>)
,当本次请求完成后会执行.whenComplete(()=>)
,可以通过.timeout(Duration(seconds:6))
设置超时时间,超时处理会来到.catchError(()=>{})
。 这个方式看似非常像iOS下的block
, 其实在java
,swift
,javascript
等语法中,这种链式调用的语法非常常见,它确实看的非常的清晰易读易懂。
刷新页面:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('待上课程'),
),
body: Container(
child: _datas.length == 0
? Center(
child: Text('数据加载中...'),
)
: 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
;
来看下最终效果图:
![](https://img.haomeiwen.com/i2019966/378b2b0027d05707.png)
总结
关于http: ^0.12.1
,本文中就是简单的应用了一个GET
的请求,其它的请求方式比如POST
,如何带参数,如何配置请求头等这里就不赘述了。http
是dart下最基础网络请求方式,其实有很多基于http
的优秀package包,还有很多序列化/反序列化的package,大家可以在上面我提供的网站中找到。