1. 程式人生 > 其它 >03、Flutter--網路請求

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請求服務
  1. 在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()}');
  }
}
  1. 開啟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;
  }
}
  1. 編寫商品列表介面,開啟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}'),
        ],
      ),
    );
  }
}