03、Flutter--網路請求
Flutter網路請求
包資源
Flutter包類似於Java語言裡的jar包,由全球眾多開發者共同提供第三方庫。
包倉庫
所有包(package)都會發布到Dart的包倉庫裡,在下面網址輸入你想使用的包後點擊搜尋即可。
包倉庫地址為:http://pub.dartlangt.org
使用包需要開啟pubspec.yaml檔案,在dependencies下新增包的名稱及版本:
點選Packages get命令來獲取工程配置檔案中所新增的引用包,或開啟命令列視窗執行flutter packages get命令。
開啟main.dart檔案,匯入url_lancher.dart包
import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart';
此時,就可以使用launch方法來開啟url地址:
import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: '使用第三方包示例', home: Scaffold( appBar: AppBar( title: Text('使用第三方包示例'), ), body: Center( child: new RaisedButton( onPressed: (){ // 指定url併發起請求 const url = 'https://www.baidu.com'; launch(url); }, ), ), ), ); } }
Http請求
Htt[協議通常用於做前後端的資料互動。Flutter請求網路有兩種方法,一種是用Http請求,另一種是用HttpClient請求。
- Http請求方式
在使用Http方式請求網路時,需要匯入http包,如下所示:
匯入庫:http: ^0.12.0+1
匯入包:import 'package:http/http.dart' as http;
下面的示例中發起一個http的get請求,並將返回的結果資訊列印到控制檯:
import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; void main() => runApp(new MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'http請求示例', home: new Scaffold( appBar: AppBar( title: Text('http請求示例'), ), body: Center( child: RaisedButton( onPressed: () { var url = 'http://httpbin.org/'; // 向url傳送get請求 http.get(url).then((response) { print("狀態: ${response.statusCode}"); print("正文: ${response.body}"); }); }, child: Text('傳送http請求'), ), ), ), ); } }
HttpClient請求方式
在使用HttpClient方式請求網路時,需要匯入io及convert包,如下所示:
import 'dart:convert';
import 'dart.io';
請看下面完整示例程式碼,示例中使用HttpClient請求了一條天氣資料,並將返回的結果資訊列印到控制檯裡。
import 'package:flutter/material.dart';
import 'dart:convert';
import 'dart:io';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// 獲取天氣資料
void getWeatherData() async {
try {
// 例項化HttpClient物件
HttpClient httpClient = new HttpClient();
// 發起請求
HttpClientRequest request = await httpClient.getUrl(
Uri.parse("http://wthrcdn.etouch.cn/weather_mini?citykey=101070101"));
// 等待伺服器返回資料
HttpClientResponse response = await request.close();
// 使用utf8.decoder從response裡解析資料
var result = await response.transform(utf8.decoder).join();
// 輸出響應頭
print(result);
httpClient.close();
} catch (e) {
print("請求失敗: $e");
} finally {
// 最後處理操作
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'httpClient請求',
home: Scaffold(
appBar: AppBar(title: Text('httpClient請求'),),
body: Center(
child: RaisedButton(
child: Text('獲取天氣資料'),
onPressed: getWeatherData,
),
),
),
);
}
}
Dio請求方式
Dio是一個強大的Dart Http請求庫,支援Restful API、Form-Data、攔截器、請求取消、Cookie管理、檔案上傳/下載、超時、自定義介面卡等。
dio: 3.0.0 #latest version
接下來編寫一個獲取商品列表資料的示例,具體結構如下所示:
main.dart // 主程式
model // 資料庫模型
good_list_model.dart // 商品列表模型
pages // 檢視層
good_list_page.dart // 商品列表頁面
service // 服務層
http_service.dart // http請求服務
- 在main.dart中的body中新增商品列表頁面元件GoodListPage。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Dio請求',
home: Scaffold(
appBar: AppBar(title: Text('Dio請求'),),
body: GoodListPage(),
),
);
}
}
2) 開啟http_service.dart,新增request方法。
import 'dart:io';
import 'package:dio/dio.dart';
// Dio請求封裝
Future request(url, {formData}) async {
try{
Response response;
Dio dio = new Dio();
dio.options.contentType = ContentType.parse('application/x-www-form-urlencoded') as String;
// 發起POST請求,傳入url及表單資料
response = await dio.post(url, data: formData);
if(response.statusCode == 200) {
return response;
}else{
throw Exception('後端介面異常,請求檢查程式碼和伺服器執行情況...');
}
}catch(e){
return print('error:::${e.toString()}');
}
}
- 開啟good_list_page.dart檔案編寫商品列表資料模型。(JSON轉Model和Model轉JSON)
// 商品列表資料模型
class GoodListModel{
// 狀態碼
String code;
// 狀態資訊
String message;
// 商品列表資料
List<GoodModel> data;
// 通過傳入json資料轉換成資料模型
GoodListModel.fromJson(Map<String, dynamic> json){
code = json['code'];
message = json['message'];
if(json['data'] != null) {
data = List<GoodModel>();
// 迴圈迭代JSON資料並將每一項資料轉換成GoodModel
json['data'].forEach((v){
data.add(GoodModel.fromJson(v));
});
}
}
// 將資料模型轉換成json
Map<String, dynamic> toJson() {
Map<String, dynamic> data = new Map();
data['code'] = this.code;
data['message'] = this.message;
if(this.data != null) {
data['data'] = this.data.map((e) => e.toJson()).toList();
}
return data;
}
}
// 商品資訊模型
class GoodModel {
// 商品圖片
String image;
// 原價
String oriPrice;
// 現有價格
String presentPrice;
// 商品名稱
String name;
// 商品id
String goodsId;
// 構造方法
GoodModel(
this.image, this.oriPrice, this.presentPrice, this.name, this.goodsId);
// 通過傳入json資料轉換成資料模型
GoodModel.fromJson(Map<String, dynamic> json){
image = json['image'];
oriPrice = json['oriPrice'];
presentPrice = json['presentPrice'];
name = json['name'];
goodsId = json['goodsId'];
}
// 將資料模型轉換成json
Map<String, dynamic> toJson() {
Map<String, dynamic> data = new Map();
data['image'] = this.image;
data['oriPrice'] = this.oriPrice;
data['presentPrice'] = this.presentPrice;
data['name'] = this.name;
data['goodsId'] = this.goodsId;
return data;
}
}
- 編寫商品列表介面,開啟good_list_page.dart檔案,新增GoodListPage元件,需要繼承StatefulWidget有狀態元件。
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_dio/model/good_list_model.dart';
import 'package:flutter_dio/service/http_service.dart';
// 商品列表頁面
class GoodListPage extends StatefulWidget {
@override
_GoodListPageState createState() => new _GoodListPageState();
}
class _GoodListPageState extends State<GoodListPage> {
// 初始化資料模型
GoodListModel goodListModel;
// 滾動控制
var scrollController = new ScrollController();
@override
initState(){
super.initState();
// 獲取商品資料
getGoods();
}
@override
Widget build(BuildContext context) {
// 通過商品列表判斷陣列長度來判斷是否有資料
if(goodListModel.data.length > 0) {
return ListView.builder(
// 列表長度
itemCount: goodListModel.data.length,
// 滾動控制器
controller: scrollController,
// 列表構造器
itemBuilder: (context, index){
return _ListWidget(goodListModel.data, index);
},
);
}else{
// 商品列表沒有資料時返回空容器
return Container();
}
}
// 獲取商品資料
Future<void> getGoods() async {
// 請求url
var url = 'http://127.0.0.1:3000/getDioData';
// 請求引數,店鋪Id
var formData = {'shopId': '001'};
// 呼叫請求方法傳入url表單資料
await request(url, formData:formData).then((value){
// 返回資料進行json解碼
var data = json.decode(value.toString());
// 列印資料
print('商品資料列表Json格式:::' + data.toString());
// 設定狀態重新整理資料
setState(() {
// 將返回的json資料轉換成Model
goodListModel = GoodListModel.fromJson(data);
});
});
}
// 商品列表項
Widget _ListWidget(List<GoodModel> list, int index) {
return Container(
padding: EdgeInsets.only(top: 5.0, bottom: 5.0),
decoration: BoxDecoration(
color: Colors.white,
border: Border(
bottom: BorderSide(width: 1.0, color: Colors.black12),
),
),
// 水平方向佈局
child: Row(
children: [
// 返回商品圖片
_goodsImage(list, index),
SizedBox(width: 10,),
// 右側使用垂直佈局
Column(
children: [
_goodsName(list, index),
_goodsPrice(list, index),
],
),
],
),
);
}
// 商品圖片
Widget _goodsImage(List<GoodModel> list, int index) {
return Container(
width: 150,
height: 150,
child: Image.network(list[index].image, fit: BoxFit.fitWidth,),
);
}
// 商品名稱
Widget _goodsName(List<GoodModel> list, int index) {
return Container(
padding: EdgeInsets.all(5.0),
width: 200,
child: Text(list[index].name, maxLines: 2, overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: 18),),
);
}
// 商品價格
Widget _goodsPrice(List<GoodModel> list, int index) {
return Container(
margin: EdgeInsets.only(top: 20.0),
width: 200,
child: Row(
children: [
Text('價格¥${list[index].presentPrice}', style: TextStyle(color: Colors.red),),
Text('¥${list[index].oriPrice}'),
],
),
);
}
}