zoukankan      html  css  js  c++  java
  • Flutter网络请求与JSON解析

    本文介绍如何在Flutter中创建HTTP网络请求和对请求的json string进行类型解析.

    • 网络请求

    官方使用的是用dart io中的HttpClient发起的请求,但HttpClient本身功能较弱,很多常用功能都不支持。

    建议使用dio 来发起网络请求,它是一个强大易用的dart http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载……

    dart:io 

     发起HTTP请求

     

    http支持位于dart:io,所以要创建一个HTTP client, 我们需要添加一个导入:

     

    import 'dart:io';
    
    var httpClient = new HttpClient();

     

    该 client 支持常用的HTTP操作, such as GETPOSTPUTDELETE.

     

    处理异步

     

    注意,HTTP API 在返回值中使用了Dart Futures。 我们建议使用async/await语法来调用API。

     

    网络调用通常遵循如下步骤:

     

    1. 创建 client.
    2. 构造 Uri.
    3. 发起请求, 等待请求,同时您也可以配置请求headers、 body。
    4. 关闭请求, 等待响应.
    5. 解码响应的内容.

     

    Several of these steps use Future based APIs. Sample APIs calls for each step above are: 其中的几个步骤使用基于Future的API。上面步骤的示例:

     

    get() async {
      var httpClient = new HttpClient();
      var uri = new Uri.http(
          'example.com', '/path1/path2', {'param1': '42', 'param2': 'foo'});
      var request = await httpClient.getUrl(uri);
      var response = await request.close();
      var responseBody = await response.transform(UTF8.decoder).join();
    }

    dio

    添加依赖

    dependencies:
      dio: ^x.x.x  // latest version

    发起一个 GET 请求 :

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

    发起一个 POST 请求:

    response=await dio.post("/test",data:{"id":12,"name":"wendu"})

    发起多个并发请求:

    response= await Future.wait([dio.post("/info"),dio.get("/token")]);

    下载文件:

    response=await dio.download("https://www.google.com/","./xx.html")

    发送 FormData:

    FormData formData = new FormData.from({
       "name": "wendux",
       "age": 25,
    });
    response = await dio.post("/info", data: formData)

    通过FormData上传多个文件:

    FormData formData = new FormData.from({
       "name": "wendux",
       "age": 25,
       "file1": new UploadFileInfo(new File("./upload.txt"), "upload1.txt")
       "file2": new UploadFileInfo(new File("./upload.txt"), "upload2.txt")
    });
    response = await dio.post("/info", data: formData)
    • JSON解析

    使用 dart:convert手动序列化JSON

    Flutter中基本的JSON序列化非常简单。Flutter有一个内置dart:convert库,其中包含一个简单的JSON编码器和解码器。

    以下是一个简单的user model的示例JSON。

    {
      "name": "John Smith",
      "email": "john@example.com"
    }

    有了dart:convert,我们可以用两种方式来序列化这个JSON model。我们来看看这两种方法:

    内连序列化JSON

    通过查看dart:转换JSON文档,我们发现可以通过调用JSON.decode方法来解码JSON ,使用JSON字符串作为参数。

    Map<String, dynamic> user = JSON.decode(json);
    
    print('Howdy, ${user['name']}!');
    print('We sent the verification link to ${user['email']}.');

    不幸的是,JSON.decode()仅返回一个Map<String, dynamic>,这意味着我们直到运行时才知道值的类型。 通过这种方法,我们失去了大部分静态类型语言特性:类型安全、自动补全和最重要的编译时异常。这样一来,我们的代码可能会变得非常容易出错。

    例如,当我们访问nameemail字段时,我们输入的很快,导致字段名打错了。但由于这个JSON在map结构中,所以编译器不知道这个错误的字段名(译者语:所以编译时不会报错)。

    在模型类中序列化JSON

    我们可以通过引入一个简单的模型类(model class)来解决前面提到的问题,我们称之为User。在User类内部,我们有:

    • 一个User.fromJson 构造函数, 用于从一个map构造出一个 User实例 map structure
    • 一个toJson 方法, 将 User 实例转化为一个map.

    这样,调用代码现在可以具有类型安全、自动补全字段(name和email)以及编译时异常。如果我们将拼写错误或字段视为int类型而不是String, 那么我们的应用程序就不会通过编译,而不是在运行时崩溃。

    user.dart

    class User {
      final String name;
      final String email;
    
      User(this.name, this.email);
    
      User.fromJson(Map<String, dynamic> json)
          : name = json['name'],
            email = json['email'];
    
      Map<String, dynamic> toJson() =>
        {
          'name': name,
          'email': email,
        };
    }
    

    现在,序列化逻辑移到了模型本身内部。采用这种新方法,我们可以非常容易地反序列化user。

    Map userMap = JSON.decode(json);
    var user = new User.fromJson(userMap);
    
    print('Howdy, ${user.name}!');
    print('We sent the verification link to ${user.email}.');

    要序列化一个user,我们只是将该User对象传递给该JSON.encode方法。我们不需要手动调用toJson这个方法,因为JSON.encode已经为我们做了。

    String json = JSON.encode(user);

    Json映射到对象

    首先要借助一个工具jsonformat 工具下载地址

    举一个例子 json文件,来自玩安卓网站

    这是一个相对很复杂的json文件

    用jsonview打开查看,这个json文件包含一个data的数组和两个变量,然后数组的每一项又包含一个数组和6个变量,然后下一级数组的每一项又包含一个数组和6个变量 
    这里写图片描述

    下面使用jsonformat 转换成dart bean文件

    打开下载的jsonformat ,将json文件copy进去点击格式化 
    这里写图片描述

    右边的红色是我们要填写的类名称,对应关系像这样,这里分别填写 tree children children ,后两个相同,点击生成bean 
    这里写图片描述

    生成代码如下

    import 'dart:convert' show json;
    
    
    class tree {
    
      int errorCode;
      String errorMsg;
      List<children> data;
    
    
      tree(jsonStr) {
      var jsonRes = json.decode(jsonStr);
    
        errorCode = jsonRes['errorCode'];
        errorMsg = jsonRes['errorMsg'];
        data = [];
    
    for (var dataItem in jsonRes['data']){
    
        data.add(new children(dataItem));
    }
    
    
      }
    
      @override
      String toString() {
        return '{"errorCode": $errorCode,"errorMsg": ${errorMsg != null?'${json.encode(errorMsg)}':'null'},"data": $data}';
      }
    }
    
    
    
    class children {
    
      int courseId;
      int id;
      int order;
      int parentChapterId;
      int visible;
      String name;
      List<children> children;
    
    
      children(jsonRes) {
        courseId = jsonRes['courseId'];
        id = jsonRes['id'];
        order = jsonRes['order'];
        parentChapterId = jsonRes['parentChapterId'];
        visible = jsonRes['visible'];
        name = jsonRes['name'];
        children = [];
    
    for (var childrenItem in jsonRes['children']){
    
        children.add(new children(childrenItem));
    }
    
    
      }
    
      @override
      String toString() {
        return '{"courseId": $courseId,"id": $id,"order": $order,"parentChapterId": $parentChapterId,"visible": $visible,"name": ${name != null?'${json.encode(name)}':'null'},"children": $children}';
      }
    }
    
    
    
    class children {
    
      int courseId;
      int id;
      int order;
      int parentChapterId;
      int visible;
      String name;
      List<dynamic> children;
    
    
      children(jsonRes) {
        courseId = jsonRes['courseId'];
        id = jsonRes['id'];
        order = jsonRes['order'];
        parentChapterId = jsonRes['parentChapterId'];
        visible = jsonRes['visible'];
        name = jsonRes['name'];
        children = [];
    
    for (var childrenItem in jsonRes['children']){
    
        children.add(childrenItem);
    }
    
    
      }
    
      @override
      String toString() {
        return '{"courseId": $courseId,"id": $id,"order": $order,"parentChapterId": $parentChapterId,"visible": $visible,"name": ${name != null?'${json.encode(name)}':'null'},"children": $children}';
      }
    }

    接下来就是在APP中请求网络,将其转换成dart bean

        ///封装的get请求 _networkUtil,可以替换成自己的请求方式
      ///发起get网络请求并且转换json
      Future<dynamic> requestGet(String url) {
        return http.get(url)
            .then((http.Response response) {
            final String res = response.body;
            final int statusCode = response.statusCode;
    
            if (statusCode < 200 || statusCode > 400 || json == null) {
              throw new Exception("Error while fetching data");
            }
            ///有值
            return _decoder.convert(res);
        });
      }
     ///这里返回的就是 Future<Tree> 对象,(fillUrl(TREE_LIST)是请求的url
      Future<Tree> fetchTree() {
        return _networkUtil.requestGet(fillUrl(TREE_LIST)).then((dynamic res) {
          ///可以这样取值
          return new Tree.map(res);
        });
      }
     
  • 相关阅读:
    angularjs学习笔记—事件指令
    JS编写点击页面弹出被点击的标签名
    对数据进行排序
    springBoot集成seata
    maven打包时根据不同的环境生成不同的jar包名称
    单列模式-双重锁校验解析
    hashmap原理简述
    Linux搭建disconf(二)
    Linux搭建dubbo-admin 分布式服务监控中心
    Linux安装zookeeper
  • 原文地址:https://www.cnblogs.com/fuyaozhishang/p/9252286.html
Copyright © 2011-2022 走看看