Flutter 中的 JSON 解析

JSON 是咱們開發中最常使用的一種數據格式,這篇文章中,咱們主要看看在開發中最多見的幾種格式的 JSON 數據在 Flutter 中的解析:git

如下案例中,咱們都會將json文件放到本地,也就是 assets 文件中,而後從本地讀取這些文件進行解析。github

如咱們須要讀取 assets/person.json :shell

那麼就須要在 pubspec.yaml 中作以下配置:json

flutter:
	uses-material-design:  true
	# 資源文件配置
	assets:
		-  assets/person.json
複製代碼

下面咱們就來解析一些常見的 Json 格式的數據。api

若是對 Dart 基礎還不是很瞭解,能夠先看看這篇文章 Dart 基礎入門數組

簡單的對象解析

定義一個 person.json 以下:異步

{
	"name":  "jack",
	"age":  18,
	"height":  175.0
}
複製代碼

和在 Java 裏面同樣,咱們首先須要構建一個 Person 的實體類,以下:async

class Person {
  String name;
  int age;
  double height;

  Person({this.name, this.age, this.height});

  factory Person.fromJson(Map<String, dynamic> json) {
    return Person(name: json['name'], age: json['age'], height: json['height']);
  }
}
複製代碼

接着,咱們在建立一個 person_service.dart 來解析 person.json。post

該類中須要導入以下幾個依賴庫:ui

// 使用該庫中的 rootBundle 對象來讀取 perosn.json 文件
import 'package:flutter/services.dart';  
// json
import 'dart:convert';  
// 異步 Future
import 'dart:async';
複製代碼

person_service.dart

import 'package:flutter/services.dart';
import 'dart:convert';
import 'dart:async';
import '../models/person.dart';

// 讀取 assets 文件夾中的 person.json 文件
Future<String> _loadPersonJson() async {
  return await rootBundle.loadString('assets/person.json');
}

// 將 json 字符串解析爲 Person 對象
Future<Person> decodePerson() async {
  // 獲取本地的 json 字符串
  String personJson = await _loadPersonJson();

  // 解析 json 字符串,返回的是 Map<String, dynamic> 類型
  final jsonMap = json.decode(personJson);

  print('jsonMap runType is ${jsonMap.runtimeType}');

  Person person = Person.fromJson(jsonMap);

  print(
      'person name is ${person.name}, age is ${person.age}, height is ${person.height}');

  return person;
}
複製代碼

輸入以下:

flutter: jsonMap runType is _InternalLinkedHashMap<String, dynamic>
flutter: person name is jack, age is 18, height is 175.0
複製代碼

能夠看出 json.decode(personJson) 方法返回的類型爲 _InternalLinkedHashMap<String, dynamic> ,意思就是這個 Map 的 key 爲 String 類型,而 value 的類型爲 dynamic 的,也就是動態的,就如 person.json 中,key 都是 String 類型的,可是 value 多是 String 、int、double 等等類型。

包含數組的對象

定義一個 country.json 以下:

{
    "name": "China",
    "cities": [
        "Beijing",
        "Shanghai"
    ]
}
複製代碼

實體類以下:

class Country {  
  String name;  
  List<String> cities;  
  
  Country({this.name, this.cities});  
  
  factory Country.fromJson(Map<String, dynamic> json) {  
  return Country(name: json['name'], cities: json['cities']);  
  }  
}
複製代碼

Service 類以下:

import 'dart:async';
import 'package:flutter/services.dart';
import 'dart:convert';
import '../models/country.dart';

Future<String> _loadCountryJson() async {
  return await rootBundle.loadString('assets/country.json');
}

Future<Country> decodeCountry() async {
  String countryJson = await _loadCountryJson();

  Map<String, dynamic> jsonMap = json.decode(countryJson);

  Country country = Country.fromJson(jsonMap);
  print('country name is ${country.name}');
  return country;
}
複製代碼

而後咱們在 main() 中去調用 decodeCountry() 運行,報錯了...

Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'List<String>'
...
複製代碼

錯誤日誌說 List<dynamic> 不是 List<String> 的子類型,也就是咱們在country的實體類中直接給 cities 屬性賦值爲 cities: json['cities'],咱們先來看看 json['cities'] 是什麼類型:

factory Country.fromJson(Map<String, dynamic> json) {  
  print('json["cities"] type is ${json['cities'].runtimeType}');  
  return Country(name: json['name'], cities: json['cities']);  
}
複製代碼

輸出以下:

flutter: json["cities"] type is List<dynamic>
複製代碼

這個時候咱們須要將 Country.fromJson(...) 方法做以下更改:

factory Country.fromJson(Map<String, dynamic> json) {
    print('json["cities"] type is ${json['cities'].runtimeType}');
    var originList = json['cities'];
    List<String> cityList = new List<String>.from(originList);
    return Country(name: json['name'], cities: cityList);
  }
複製代碼

上述代碼中,咱們建立了一個 List<String> 類型的數組,而後將 List<dynamic> 數組中的元素都添加到了 List<String> 中。輸出以下:

flutter: json["cities"] type is List<dynamic>
flutter: country name is China
複製代碼

對象嵌套

定義一個 shape.json ,格式以下:

{  
  "name": "rectangle",  
  "property": {  
  "width": 5.0,  
  "height": 10.0  
  }  
}
複製代碼

實體以下:

class Shape {  
  String name;  
  Property property;  
  
  Shape({this.name, this.property});  
  
  factory Shape.fromJson(Map<String, dynamic> json) {  
  return Shape(name: json['name'], property: json['property']);  
  }  
}  
  
class Property {  
  double width;  
  double height;  
  
  Property({this.width, this.height});  
  
  factory Property.fromJson(Map<String, dynamic> json) {  
  return Property(width: json['width'], height: json['height']);  
  }  
}
複製代碼

Service 類以下:

import 'dart:async';  
import 'dart:convert';  
import 'package:flutter/services.dart';  
import '../models/shape.dart';  
  
Future<String> _loadShapeJson() async {  
  return await rootBundle.loadString('assets/shape.json');  
}  
  
Future<Shape> decodeShape() async {  
  String shapeJson = await _loadShapeJson();  
  
  Map<String, dynamic> jsonMap = json.decode(shapeJson);  
  
  Shape shape = Shape.fromJson(jsonMap);  
  
  print('shape name is ${shape.name}');  
  return shape;  
}
複製代碼

運行以後,會報以下錯誤:

Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Property'
複製代碼

也就是說 property: json['property'] 這裏賦值的類型是 _InternalLinkedHashMap<String, dynamic> 而不是 Propertyjson['property'] 的值是這樣的 {width: 5.0, height: 10.0},它是一個 Map ,並非一個 Property 對象,咱們須要先將這個 Map 轉化爲對象,而後在賦值:

factory Shape.fromJson(Map<String, dynamic> json) {  
  print('json["property"] is ${json['property']}');  
  Property property = Property.fromJson(json['property']);   // new line
  return Shape(name: json['name'], property: property);  
}
複製代碼

輸出:

shape name is rectangle
複製代碼

複雜的對象數組嵌套

{
  "id": "0302",
  "class_name": "三年二班",
  "students": [
    {
      "name": "葉湘倫",
      "sex": "男"
    },
    {
      "name": "路小雨",
      "sex": "女"
    }
  ]
}
複製代碼

實體:

class ClassInfo {
  String id;
  String name;
  List<Student> studentList;

  ClassInfo({this.id, this.name, this.studentList});

  factory ClassInfo.fromJson(Map<String, dynamic> json) {
    return ClassInfo(
        id: json['id'],
        name: json['class_name'],
        studentList: json['students']);
  }
}

class Student {
  String name;
  String sex;

  Student({this.name, this.sex});

  factory Student.fromJson(Map<String, dynamic> json) {
    return Student(name: json['name'], sex: json['sex']);
  }
}
複製代碼

service:

import 'dart:async';
import 'dart:convert';
import 'package:flutter/services.dart';
import '../models/class_info.dart';

Future<String> _loadClassInfoJson() async {
  return await rootBundle.loadString('assets/class_info.json');
}

Future<ClassInfo> decodeClassInfo() async {
  String classInfoJson = await _loadClassInfoJson();

  Map<String, dynamic> jsonMap = json.decode(classInfoJson);

  ClassInfo classInfo = ClassInfo.fromJson(jsonMap);
  classInfo.studentList
      .forEach((student) => print('student name is ${student.name}'));
  return classInfo;
}
複製代碼

上述代碼在運行後仍是會報錯:

Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'List<Student>'
複製代碼

一樣,仍是在 studentList: json['students'] 出問題了,咱們把 json['students'] 的輸出來看看:

[{name: 葉湘倫, sex: 男}, {name: 路小雨, sex: 女}]
複製代碼

上述結果的類型爲 List<dynamic> 。如今咱們須要將 List<dynamic> 轉換到一個 List<Student> 類型的數組中,這裏須要用到一個操做符 mapmap 操做符的做用就是將某種類型轉換爲另外一種類型。以下:

factory ClassInfo.fromJson(Map<String, dynamic> json) {  
  final originList = json['students'] as List;  
  List<Student> studentList =  
      originList.map((value) => Student.fromJson(value)).toList();  
  return ClassInfo(  
  id: json['id'], name: json['class_name'], studentList: studentList);  
}
複製代碼

輸出:

flutter: student name is 葉湘倫
flutter: student name is 路小雨
複製代碼

單純的數組

member.json

[
  {
    "id": 1,
    "name": "Jack"
  },
  {
    "id": 2,
    "name": "Rose"
  },
  {
    "id": 3,
    "name": "Karl"
  }
]
複製代碼

實體:

class MemberList {  
  List<Member> memberList;  
  
  MemberList({this.memberList});  
  
  factory MemberList.fromJson(List<dynamic> listJson) {  
  
  List<Member> memberList =  
        listJson.map((value) => Member.fromJson(value)).toList();  
  
  return MemberList(memberList: memberList);  
  }  
}  
  
class Member {  
  int id;  
  String name;  
  
  Member({this.id, this.name});  
  
  factory Member.fromJson(Map<String, dynamic> json) {  
  return Member(id: json['id'], name: json['name']);  
  }  
}
複製代碼

由於 member.json 是一個單純的數組,因此上述代碼中咱們建立了一個 MemberList 類來將這個 Member 數組包含起來。

注意下上述代碼中 MemberList.fromJson(...) 中的寫法。

service:

import 'dart:async';
import 'package:flutter/services.dart';
import 'dart:convert';
import '../models/member.dart';

Future<String> _loadMemberJson() async {
  return await rootBundle.loadString('assets/member.json');
}

Future<MemberList> decodeMemberList() async {
  String memberListJson = await _loadMemberJson();

  List<dynamic> list = json.decode(memberListJson);

  MemberList memberList = MemberList.fromJson(list);

  memberList.memberList
      .forEach((member) => print('member name is ${member.name}'));

  return memberList;
}
複製代碼

輸出:

flutter: member name is Jack
flutter: member name is Rose
flutter: member name is Karl
複製代碼

複雜的 Json 解析

以前的文章 Flutter 中 ListView 的使用 中用到了 豆瓣API ,這個 API 中返回的數據包含了當前熱播的電影,你們嘗試着按需解析一下吧 !!!

若有錯誤,還請指出。謝謝!!!

源碼地址

參考連接:

medium.com/flutter-com…

github.com/flutter/flu…

相關文章
相關標籤/搜索