【dart學習】-- Dart之JSON

概述

  如今很難想象移動應用程序不須要與後臺交互或者存儲結構化數據。如今開發,數據傳輸方式基本都是用JSON,在Flutter中是沒有GSON/Jackson/Moshi這些庫,由於這些庫須要運行時反射,在Flutter是禁用的。運行時反射會干擾Dart的_tree shaking_。使用_tree shaking_,能夠在發版是"去除"未使用的代碼,來優化軟件的大小。因爲反射會默認使用全部代碼,所以_tree shaking_會很難工做,這些工具沒法知道哪些widget在運行時未被使用,所以冗餘代碼很難剝離,使用反射時,應用尺寸沒法輕鬆進行優化,雖然不能在Flutter使用運行時反射,但有些庫提供了類型簡單易用的API,但它們是基於代碼生成的。下面學學在Flutter中如何操做JSON數據的使用JSON有兩個常規策略:json

  1. 手動序列化和反序列化
  2. 經過代碼生成自動序列化和反序列化 不一樣的項目有不一樣的複雜度和場景,針對於小的項目,使用代碼生成器可能會殺豬用牛刀了。對於具備多個JSON model的複雜應用程序,手動序列化可能會比較繁瑣,且容易出錯。

1.手動序列化JSON

Flutter中基本的JSON序列化很是簡單,Flutter有一個內置的dart:convert庫,其中包含一個簡單的JSON解碼器和編碼器。下面簡單實現一下:安全

1.1.內連序列化JSON

首先記得導庫:函數

import 'dart:convert';

而後根據字符串解析:工具

//內連序列化JSON
decodeJson() {
    var data= '{"name": "Knight","email": "Knight@163.com"}';
    Map<String,dynamic> user = json.decode(data);
    //輸出名字
    print("Hello,my name is ${user['name']}");
    //輸出郵箱
    print("Hello,This is my email ${user['email']}");
}

結果輸出:優化

I/flutter ( 5866): Hello,my name is Knight
I/flutter ( 5866): Hello,This is my email Knight@163.com

  這樣,能夠得到咱們想要的數據了,我以爲這種方法很實用又能簡單理解,可是不幸的是,JSON.decode()僅返回一個Map<String,dynamci>,這意味着當直到運行才知道值的類型,這種方法會失去大部分靜態類型語言特性:類型安全、自動補全和編譯時異常。這樣的話,代碼變得很是容易出錯,就好像上面咱們訪問name字段,打字打錯了,達成namr。可是這個JSON在map結構中,編譯器不知道這個錯誤的字段名(編譯時不會報錯)。爲了解決所說的問題,模型類中序列化JSON的做用出來了。ui

1.2.模型類中序列化JSON

    經過引入一個簡單的模型類(model class)來解決前面提到的問題,創建一個User類,在類內部有兩個方法:this

  1. User.fromJson構造函數,用於從一個map構造出一個User實例map structure
  2. toJson方法,將User實例化一個map 這樣調用的代碼就具備類型安全、自動補全和編譯時異常,當拼寫錯誤或字段類型視爲其餘類型,程序不會經過編譯,那就避免運行時崩潰。
1.2.1.user.dart

新建一個model文件夾,用來放實體,在其文件下新建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,
    };
}

調用以下:spa

import 'model/User.dart';//記得添加
....
//使用模型類反序列化
decodeModelJson(){
  var data= '{"name": "Knight","email": "Knight@163.com"}';
  Map userMap = json.decode(data);
  var user = new User.fromJson(userMap);
  //打印出名字
  print("Hello,my name is ${user.name}");
  //打印出郵箱
  print("Hello,my name is ${user.email}");
}

把序列化邏輯到移到模型自己內部,採用這種方法,反序列化數據就很簡單了。序列化一個user,只是將User對象傳遞給該JSON.encode方法:命令行

//序列化一個user
encodeModelJson(){
  var user = new User("Knight","Knight163.com");
  String user_json = json.encode(user);
  print(user_json);
}

結果輸出:

I/flutter ( 6684): {"name":"Knight","email":"Knight163.com"}

2.使用代碼生產庫序列化JSON

下面使用json_serializable package包,它是一個自動化的源代碼生成器,能夠爲開發者生成JSON序列化魔板。

2.1.添加依賴

要包含json_serializable到項目中,須要一個常規和兩個開發依賴項,開發依賴項是不包含在應用程序源代碼中的依賴項:

dependencies:
  # Your other regular dependencies here
  json_annotation: ^2.0.0

dev_dependencies:-->開發依賴項
  # Your other dev_dependencies here
  build_runner: ^1.1.3 -->最新版本1.2.8 由於我sdk版本比較低 因此用低版本
  json_serializable: ^2.0.2

2.2.代碼生成

有兩種運行代碼生成器的方法:

  1. 一次性生成,在項目根目錄運行flutter packages pub run build_runner build,能夠在須要爲咱們的model生成json序列化代碼。這觸發一次性構建,它經過源文件,挑選相關的併爲它們生成必要的序列化代碼。這個很是方便,可是若是咱們不須要每次在model類中進行更改都要手動運行構建命令的話會更好。
  2. 持續生成,使用_watcher_可使源代碼生成的過程更加方便,它會監視項目中文化的變化,並在須要時自動構建必要的文件,經過flutter packages pub run build_runner watch在項目根目錄運行啓動_watcher_,只需啓動一次觀察器,而後並讓它在後臺運行,這是安全的。

將上面的User.dart修改爲下面:

import 'package:json_annotation/json_annotation.dart';
part 'User.g.dart';-->一開始爆紅
//這個標註是告訴生成器,這個類是須要生成Model類的
@JsonSerializable()
class User{
  User(this.name, this.email);

  String name;
  String email;
  
  factory User.fromJson(Map<String, dynamic> json){--->一開始爆紅
     return _$UserFromJson(json);
  }
  
  Map<String, dynamic> toJson() { --->一開始爆紅
    return _$UserToJson(this);
  }
}

下面就用一次性生成命令,在項目根目錄打開命令行執行:

 

 

最後發現會在當前目錄生成User.g.dart文件:

裏面的內容能夠本身去看看看,就是反序列化/序列化的操做。注意:沒生成User.g.dart執行多幾回命令便可。最後經過json_serializable方式反序列化JSON字符串,不須要對先前代碼修改:

2.3.反序列化

  var data= '{"name": "Knight","email": "Knight@163.com"}';
  Map userMap = json.decode(data);
  var user = new User.fromJson(userMap);
  //打印出名字
  print("Hello,my name is ${user.name}");
  //打印出郵箱
  print("Hello,my name is ${user.email}");

2.4.序列化

  var user = new User("Knight","Knight163.com");
  String user_json = json.encode(user);
  print(user_json);

結果是跟上面同樣,不過這種方式額外多了生成一個文件...

相關文章
相關標籤/搜索