flutter json数据处理

2,819 阅读5分钟

本文涉及的业务场景

只要我们的app不是单机的,那么必然涉及到远程服务器数据请求。在flutter中,发起请求已经有现成的包dio了,使用起来也非常简练方便,如还是不是很了解,可以点击查看dio的详细文档

发起请求,拿到服务端返回的json数据后,接下来的步骤是怎么样的。flutter(应该说是Dart)可不像javascript那样,对json天生友好。这就是本文要讲的主要内容。你将会学到:

  • flutter项目json数据处理的详细步骤和踩坑提醒
  • json_serializable环节,命令行+工具,帮你自动化生成相关代码,无需手敲,无需手敲(重要的事情说两遍)
  • 数据和源码都为你准备妥当,无需手敲(即使小白,也可以轻松上手)

json数据读取和处理

请求回来数据后,下一步必然就是读取其中的数据信息,然后依此进行界面展示和逻辑处理了。

如果返回来的是简单的数据,而且业务逻辑也很简单,那么其实处理方式也可以简单化,例如服务端返回数据如下:

    {
        code: 200,
        message: null,
        value: true
    }

那么,你甚至可以这么处理:

    if (jsonStr.indexOf('true') != -1) {
        // do something
    }

总结的说,在这种场景下面,使用正则表达式匹配或者简单字符串处理逻辑,进行简单快速的实现,也不失为一种好方法。

json反序列化

但是,当数据结构足够复杂(例如:点击查看复杂数据示例),那么上述的方式显然就有点捉襟见肘了。

这个时候,就该轮到本文要讲述的重点,json反序列化上场了。关于序列化和反序列化,可以上网查一下,有很多资料(实在不想查,好吧,这里有现成的,点击序列化凑合着看一下吧...)。

在本文描述的业务场景下面,也可以简单理解为,我们要做的,就是把通过dio拿到的服务端json字符串数据,转换为对象,然后就可以愉快的访问该对象中的字段值了。

主要的步骤有两个:

  • json字符串转换为Map对象
  • 使用json_serializable进行反序列化

具体步骤如下:

  • 添加依赖

参考下面代码,往pubspec.yaml文件中添加json_annotationjson_serializablebuild_runner包。

dependencies:
  flutter:
    sdk: flutter
  
  json_annotation: ^3.0.0

dev_dependencies:
  flutter_test:
    sdk: flutter
  
  json_serializable: ^3.2.0
  build_runner: ^1.6.5

添加完,记得flutter packages get

  • 使用在线代码生成工具把json生成dart代码,代码命名为xxxx.dart(文件一,会在下文的代码中引用到)copy到项目中

如果你已经看过其他相关文章,很有可能是要你根据json数据写一个dart的实体类,其实,也可以的,选择你喜欢方式就行了。本文推荐工具生成,方便快捷,不易出错,哈哈。。。

如果,你还没来得及准备好试验的json数据,点击本文为你提供的数据示例,copy到工具中,愉快的玩耍吧。

  • 在当前项目的目录下运行flutter packages pub run build_runner build,命令执行完成,根据刚刚的xxxx.dart生成xxxx.g.dart(该文件生成后不要手动改,也无需引用,放着不动就是了)
  • 开始编码
import 'dart:convert';
import 'package:xxxxxxx/xxxx.dart'; //引入上面提及的文件一

String jsonStr = '{"value":1}'; //你要进行反序列化的json字符串
Map<String ,dynamic> map = json.decode(jsonStr); //先转成Map
           
MyObject obj = MyObject.fromJson(map); //假设class名为MyObject,这个根据实际情况调整
print(obj.value);

到此,基本就完成了数据的反序列化。上述代码中,主要是两个步骤:

  • String to Map
  • Map to MyObject

MyObject即引入的“文件一”中的类名,可根据实际情况进行调整。

也可能你会有疑问,既然原生已经提供了String to Map,那么只做到这一步,然后使用map对象进行接下来的coding,ok吗。

其实,也是可以的,只是。。。,下面举个列子对比一下,便一目了然了。以该数据示例为例,下面两行代码,访问的字段是一样的:

print(homePageList.value[0].modules[0].items[1].title);

print(map.entries.elementAt(2).value[0].entries.elementAt(5).value[0].entries.elementAt(11).value[1].entries.elementAt(0).value);

不知你喜欢哪种方式呢。。。

复杂不规则数据处理

按照上述的具体步骤,基本可以处理大部分的规则数据了,但是当你以数据示例为数据源,一步一步操作coding完,访问其中某些字段的值时,意想不到的事情发生了:

print(homePageList.value[0].modules[0].items[1].title); //正常打印

print(homePageList.value[0].modules[2].items[0].name); // 报错

报错信息:

The following NoSuchMethodError was throw building BlockRowFrame(dirty):
Class 'Modules' has no instance getter 'title'.
...

The following NoSuchMethodError was throw building BlockRowFrame(dirty)

这是因为,数据每一项的结构不一致导致的。数据示例中,字段name在前两个modulesitems元素中并没有,而在第三个modulesitems元素中,却有了。

遇到这种情况,只需要在用工具生成的"文件一"中对应的class,手动添加上对应的字段代码,然后再重新运行一次flutter packages pub run build_runner build --delete-conflicting-outputs便可。

到此,关于flutter json数据处理分享就讲完了。码字不易,觉得此文对你有帮助的,麻烦点个赞鼓励鼓励。

后记

如果还有不清楚的地方。。。

没关系,源码伺候,点击flutter_examples访问对应的github项目,其中的“json格式请求结果反序列化与使用(dio & json_serializable demo)”实例,就是本文的代码实现!