美文网首页Android开发经验谈Android技术知识Android进阶之路
Flutter基础:网络请求(Dio)与JSON数据解析

Flutter基础:网络请求(Dio)与JSON数据解析

作者: 字节跳不动 | 来源:发表于2021-01-09 21:23 被阅读0次

    成为一名优秀的Android开发,需要一份完备的知识体系,在这里,让我们一起成长为自己所想的那样~。

    前言

    在Android开发中如果我们想要请求网络,可以使用HttpClent、HttpURLConnection,但在项目中一般都会使用OkHttp和Retrofit。在Flutter也是如此,系统提供了HttpClient,但在项目中一般会使用第三方库,比如http和Dio,如果你想找到更多的第三库,可以在pub.dartlang.org/ 上查找想要的库。本篇文章以Dio为例,另外还会介绍JSON数据解析方面的知识。

    1.Dio的使用入门

    Dio是一个强大的Dart Http请求库,支持拦截器,全局配置,FormData,请求取消,文件下载,超时等。

    添加依赖 在pubspec.yaml中添加依赖。

    dependencies:
      dio: 2.1.7  
    复制代码
    

    官网给出了一个简单的例子:

    import 'package:dio/dio.dart';
    void getHttp() async {
      try {
        Response response = await Dio().get("http://liuwangshu.com");
        print(response);
      } catch (e) {
        print(e);
      }
    }
    复制代码
    

    如果想要发送一个GET请求:

    Response response;
    response=await dio.get("/test?id=3&name=liuwangshu")
    print(response.data.toString());
    // 请求参数也可以通过对象传递,上面的代码等同于:
    response=await dio.get("/test",data:{"id":3,"name":"liuwangshu"})
    print(response.data.toString());
    复制代码
    

    发送一个POST 请求:

    response=await dio.post("/test",data:{"id":3,"name":"liuwangshu"})
    复制代码
    

    发送一个FormData:

    FormData formData = new FormData.from({
        "name": "liuwangshu",
        "age": 18,
      });
    response = await dio.post("/info", data: formData);
    复制代码
    

    还有很多示例在github上,地址为:github.com/flutterchin…

    2.Dio访问网络的例子

    import 'dart:convert';
    import 'dart:io';
    import 'package:dio/dio.dart';
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: MyHomePage(),
        );
      }
    }
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key}) : super(key: key);
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      var _ipAddress = 'Unknown';
    
      _getIPAddress() async {//1
        var url = 'https://httpbin.org/ip';
        Dio _dio = Dio();
        String result;
        try {
          var response = await _dio.get(url);//2
          if (response.statusCode == HttpStatus.ok) {
            var data= jsonDecode(response.toString());//3
            result = data['origin'];
          } else {
            result =
            'Error getting IP status ${response.statusCode}';
          }
        } catch (exception) {
          result =exception.toString();
        }
        if (!mounted) return;
        setState(() {
          _ipAddress = result;//4
        });
      }
    
      @override
      Widget build(BuildContext context) {
        var spacer = SizedBox(height: 10.0);
        return Scaffold(
          body: Padding(
            padding: EdgeInsets.all(100.0),
            child: Column(
              children: <Widget>[
                Text('IP地址为:'),
                spacer,
                Text('$_ipAddress'),
                spacer,
               RaisedButton(
                  onPressed: _getIPAddress,
                  child: Text('请求网络'),
                ),
              ],
            ),
          ),
        );
      }
    }
    复制代码
    

    async和await是Dart语言用来支持异步编程的关键字,注释1处的async关键字使得_getIPAddress方法变为了异步方法,注释2处的await关键字只能在异步方法中使用,它使得注释2处后面的代码等到get请求返回后再执行。 如果网络请求返回的状态码为200,就在注释3处进行Json解析,将结果赋值给result变量。 当我们点击界面上按钮时,会调用_getIPAddress方法,在注释4处将请求的结果赋值给_ipAddress并显示在Text中。 网络请求成功后,效果如下图。

    3.JSON数据解析

    常用的JSON数据解析方式主要有三种,这里分别介绍下。

    3.1 使用json.decode()方法

    第2小节的例子用到的就是json.decode()方法,需要引入dart:convert库。json.decode() 方法会将 String类型数据解析成Map数据结构:Map<String, dynamic>, 取数据的格式为object[key]。 上面例子中返回的JOSN数据为:

    {
      "origin": "111.193.7.70, 111.193.7.70"
    }
    复制代码
    

    对于不复杂的JOSN数据使用json.decode()方法是一个不错的选择,但实际项目中的JOSN数据会复杂一些,如果每次取数据都用object[key],那么很容易出错。

    3.2手动编写实体类

    用一个model来保存数据,使得数据序列化。 我们可以新建一个ip.dart:

    class Ip {
      String origin;
    
      Ip(this.origin);
    
      Ip.fromJson(Map<String, dynamic> json) : origin = json['origin'];
    
      Map<String, dynamic> toJson() => {
            "origin": origin,
          };
    }
    复制代码
    

    然后修改main.dart:

    import 'dart:convert';
    import 'dart:io';
    import 'package:dio/dio.dart';
    import 'package:flutter/material.dart';
    import 'model/ip.dart';
    ...
    class _MyHomePageState extends State<MyHomePage> {
      var _ipAddress = 'Unknown';
      _getIPAddress() async {
        var url = 'https://httpbin.org/ip';
        Dio _dio = Dio();
        String result;
        try {
          var response = await _dio.get(url);
          if (response.statusCode == HttpStatus.ok) {
            var data= jsonDecode(response.toString());
            var ip=Ip.fromJson(data);//1
            result = ip.origin;
          } 
        ...
      }
    ...
    }
    复制代码
    

    注释1处通过Ip.fromJson就可以获取ip的实体,这样就可以完成赋值等操作了。

    3.3 自动生成实体类

    一般项目中Json数据会比较繁多,每次重复写实体类的模版代码显然枯燥无意义,可以使用一些工具来生成实体类。 比如使用网页自动生成: app.quicktype.io/ 。转换的实体类如下所示。

    import 'dart:convert';
    
    Ip ipFromJson(String str) => Ip.fromJson(json.decode(str));
    
    String ipToJson(Ip data) => json.encode(data.toJson());
    
    class Ip {
        String origin;
    
        Ip({
            this.origin,
        });
    
        factory Ip.fromJson(Map<String, dynamic> json) => new Ip(
            origin: json["origin"],
        );
    
        Map<String, dynamic> toJson() => {
            "origin": origin,
        };
    }
    复制代码
    

    除了使用网页生成,还可以使用开源的JSONFormat4Flutter: github.com/debuggerx01…

    使用json_serializable
    除了以上提到的工具,还可以使用json_serializable。 json_serializable是一个自动化的源代码生成器,可以方便的生成JSON实体类。 首先在pubspec.yaml加入如下依赖,

    dependencies:
      json_annotation: ^2.4.0
    
    dev_dependencies:
      build_runner: ^1.0.0
      json_serializable: ^3.0.0
    
    复制代码
    

    在AS的Terminal中运行flutter packages get命令,用来在项目中使用这些新的依赖项。 接着实现ip实体类。

    import 'package:json_annotation/json_annotation.dart';
    
    // ip.g.dart 将在我们运行生成命令后自动生成
    part 'ip.g.dart';
    
    //告诉生成器,这个类需要生成Model类
    @JsonSerializable()
    class Ip{
      Ip(this.origin);
    
      String origin;
    
      factory Ip.fromJson(Map<String, dynamic> json) => _$IpFromJson(json);
      Map<String, dynamic> toJson() => _$IpToJson(this);
    }
    复制代码
    

    关键的在于@JsonSerializable(),它用于告诉生成器,Ip类是需要生成的Model类。在Terminal窗口运行如下命令生成ip.g.dart文件。

    flutter packages pub run build_runner build
    复制代码
    

    如何使用见3.2节就可以了,使用json_serializable可以让我们忽略Ip类中的任何手动JSON序列化 。源代码生成器会在同一个目录下生成Ip.g.dart,如下所示。

    // GENERATED CODE - DO NOT MODIFY BY HAND
    
    part of 'ip.dart';
    
    // **************************************************************************
    // JsonSerializableGenerator
    // **************************************************************************
    
    Ip _$IpFromJson(Map<String, dynamic> json) {
      return Ip(json['origin'] as String);
    }
    
    Map<String, dynamic> _$IpToJson(Ip instance) =>
        <String, dynamic>{'origin': instance.origin};
    复制代码
    

    该文件有着必需的序列化逻辑,目前Flutter官方推荐的就是使用json_serializable。

    作者:刘望舒
    链接:https://juejin.cn/post/6844903902182113288
    来源:掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    相关文章

      网友评论

        本文标题:Flutter基础:网络请求(Dio)与JSON数据解析

        本文链接:https://www.haomeiwen.com/subject/ykdhaktx.html