新聞中心
種JSON序列化方法適合我?
本文介紹了使用JSON的兩個(gè)常規(guī)策略:

成都創(chuàng)新互聯(lián)專(zhuān)注于廣南企業(yè)網(wǎng)站建設(shè),響應(yīng)式網(wǎng)站,商城網(wǎng)站建設(shè)。廣南網(wǎng)站建設(shè)公司,為廣南等地區(qū)提供建站服務(wù)。全流程定制網(wǎng)站開(kāi)發(fā),專(zhuān)業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,成都創(chuàng)新互聯(lián)專(zhuān)業(yè)和態(tài)度為您提供的服務(wù)
- 手動(dòng)序列化和反序列化
- 通過(guò)代碼生成自動(dòng)序列化和反序列化
不同的項(xiàng)目具有不同的復(fù)雜度和場(chǎng)景。對(duì)于較小項(xiàng)目,使用代碼生成器可能會(huì)過(guò)度。對(duì)于具有多個(gè)JSON model的復(fù)雜應(yīng)用程序,手動(dòng)序列化可能會(huì)比較重復(fù),并會(huì)很容易出錯(cuò)。
小項(xiàng)目手動(dòng)序列化
手動(dòng)JSON序列化是指使使用dart:convert中內(nèi)置的JSON解碼器。它將原始JSON字符串傳遞給JSON.decode() 方法,然后在返回的Map
當(dāng)您的項(xiàng)目變大時(shí),手動(dòng)編寫(xiě)序列化邏輯可能變得難以管理且容易出錯(cuò)。如果您在訪(fǎng)問(wèn)未提供的JSON字段時(shí)輸入了一個(gè)錯(cuò)誤的字段,則您的代碼將會(huì)在運(yùn)行時(shí)會(huì)引發(fā)錯(cuò)誤。
如果您的項(xiàng)目中JSON model并不多,并且希望快速測(cè)試一下,那么手動(dòng)序列化可能會(huì)很方便。
在大中型項(xiàng)目中使用代碼生成
代碼生成功能的JSON序列化是指通過(guò)外部庫(kù)為您自動(dòng)生成序列化模板。它需要一些初始設(shè)置,并運(yùn)行一個(gè)文件觀察器,從您的model類(lèi)生成代碼。 例如,json_serializable和built_value就是這樣的庫(kù)。
這種方法適用于較大的項(xiàng)目。不需要手寫(xiě),如果訪(fǎng)問(wèn)JSON字段時(shí)拼寫(xiě)錯(cuò)誤,這會(huì)在編譯時(shí)捕獲的。代碼生成的不利之處在于它涉及到一些初始設(shè)置。另外,生成的源文件可能會(huì)在項(xiàng)目導(dǎo)航器會(huì)顯得混亂。
當(dāng)您有一個(gè)中型或大型項(xiàng)目時(shí),您可能想要使用代碼生成JSON序列化。
Flutter中是否有GSON / Jackson / Moshi?
簡(jiǎn)單的回答是沒(méi)有.
這樣的庫(kù)需要使用運(yùn)行時(shí)反射,這在Flutter中是禁用的。運(yùn)行時(shí)反射會(huì)干擾Dart的_tree shaking_。使用_tree shaking_,我們可以在發(fā)版時(shí)“去除”未使用的代碼。這可以顯著優(yōu)化應(yīng)用程序的大小。
由于反射會(huì)默認(rèn)使用所有代碼,因此_tree shaking_會(huì)很難工作。這些工具無(wú)法知道哪些widget在運(yùn)行時(shí)未被使用,因此冗余代碼很難剝離。使用反射時(shí),應(yīng)用尺寸無(wú)法輕松的進(jìn)行優(yōu)化。
dartson呢?
dartson 使用了運(yùn)行時(shí)反射 runtime,所以不能在Flutter中使用它.
雖然我們不能在Flutter中使用運(yùn)行時(shí)反射,但有些庫(kù)為我們提供了類(lèi)似易于使用的API,但它們是基于代碼生成的。這種方法在代碼生成庫(kù)部分有更詳細(xì)的介紹。
使用 dart:convert手動(dòng)序列化JSON
Flutter中基本的JSON序列化非常簡(jiǎn)單。Flutter有一個(gè)內(nèi)置dart:convert庫(kù),其中包含一個(gè)簡(jiǎn)單的JSON編碼器和解碼器。
以下是一個(gè)簡(jiǎn)單的user model的示例JSON。
{
"name": "John Smith",
"email": "[email protected]"
}
有了dart:convert,我們可以用兩種方式來(lái)序列化這個(gè)JSON model。我們來(lái)看看這兩種方法:
內(nèi)連序列化JSON
通過(guò)查看dart:轉(zhuǎn)換JSON文檔,我們發(fā)現(xiàn)可以通過(guò)調(diào)用JSON.decode方法來(lái)解碼JSON ,使用JSON字符串作為參數(shù)。
Map user = JSON.decode(json);
print('Howdy, ${user['name']}!');
print('We sent the verification link to ${user['email']}.');
不幸的是,JSON.decode()僅返回一個(gè)Map
例如,當(dāng)我們?cè)L問(wèn)name或email字段時(shí),我們輸入的很快,導(dǎo)致字段名打錯(cuò)了。但由于這個(gè)JSON在map結(jié)構(gòu)中,所以編譯器不知道這個(gè)錯(cuò)誤的字段名(譯者語(yǔ):所以編譯時(shí)不會(huì)報(bào)錯(cuò))。
在模型類(lèi)中序列化JSON
我們可以通過(guò)引入一個(gè)簡(jiǎn)單的模型類(lèi)(model class)來(lái)解決前面提到的問(wèn)題,我們稱(chēng)之為User。在User類(lèi)內(nèi)部,我們有:
- 一個(gè)User.fromJson 構(gòu)造函數(shù), 用于從一個(gè)map構(gòu)造出一個(gè) User實(shí)例 map structure
- 一個(gè)toJson 方法, 將 User 實(shí)例轉(zhuǎn)化為一個(gè)map.
這樣,調(diào)用代碼現(xiàn)在可以具有類(lèi)型安全、自動(dòng)補(bǔ)全字段(name和email)以及編譯時(shí)異常。如果我們將拼寫(xiě)錯(cuò)誤或字段視為int類(lèi)型而不是String, 那么我們的應(yīng)用程序就不會(huì)通過(guò)編譯,而不是在運(yùn)行時(shí)崩潰。
user.dart
class User {
final String name;
final String email;
User(this.name, this.email);
User.fromJson(Map json)
: name = json['name'],
email = json['email'];
Map toJson() =>
{
'name': name,
'email': email,
};
}
現(xiàn)在,序列化邏輯移到了模型本身內(nèi)部。采用這種新方法,我們可以非常容易地反序列化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}.');
要序列化一個(gè)user,我們只是將該User對(duì)象傳遞給該JSON.encode方法。我們不需要手動(dòng)調(diào)用toJson這個(gè)方法,因?yàn)镴SON.encode已經(jīng)為我們做了。
String json = JSON.encode(user);
這樣,調(diào)用代碼就不用擔(dān)心JSON序列化了。但是,model類(lèi)還是必須的。在生產(chǎn)應(yīng)用程序中,我們希望確保序列化正常工作。在實(shí)踐中,User.fromJson和User.toJson方法都需要單元測(cè)試到位,以驗(yàn)證正確的行為。
另外,實(shí)際場(chǎng)景中,JSON對(duì)象很少會(huì)這么簡(jiǎn)單,嵌套的JSON對(duì)象并不罕見(jiàn)。
如果有什么能為我們自動(dòng)處理JSON序列化,那將會(huì)非常好。幸運(yùn)的是,有!
使用代碼生成庫(kù)序列化JSON
盡管還有其他庫(kù)可用,但在本教程中,我們使用了json_serializable package包。 它是一個(gè)自動(dòng)化的源代碼生成器,可以為我們生成JSON序列化模板。
由于序列化代碼不再由我們手寫(xiě)和維護(hù),我們將運(yùn)行時(shí)產(chǎn)生JSON序列化異常的風(fēng)險(xiǎn)降至最低。
在項(xiàng)目中設(shè)置json_serializable
要包含json_serializable到我們的項(xiàng)目中,我們需要一個(gè)常規(guī)和兩個(gè)開(kāi)發(fā)依賴(lài)項(xiàng)。簡(jiǎn)而言之,開(kāi)發(fā)依賴(lài)項(xiàng)是不包含在我們的應(yīng)用程序源代碼中的依賴(lài)項(xiàng)。
通過(guò)此鏈接可以查看這些所需依賴(lài)項(xiàng)的最新版本 。
pubspec.yaml
dependencies:
# Your other regular dependencies here
json_annotation: ^2.0.0
dev_dependencies:
# Your other dev_dependencies here
build_runner: ^1.0.0
json_serializable: ^2.0.0
在您的項(xiàng)目根文件夾中運(yùn)行 flutter packages get (或者在編輯器中點(diǎn)擊 “Packages Get”) 以在項(xiàng)目中使用這些新的依賴(lài)項(xiàng).
以json_serializable的方式創(chuàng)建model類(lèi)
讓我們看看如何將我們的User類(lèi)轉(zhuǎn)換為一個(gè)json_serializable。為了簡(jiǎn)單起見(jiàn),我們使用前面示例中的簡(jiǎn)化JSON model。
user.dart
import 'package:json_annotation/json_annotation.dart';
// user.g.dart 將在我們運(yùn)行生成命令后自動(dòng)生成
part 'user.g.dart';
///這個(gè)標(biāo)注是告訴生成器,這個(gè)類(lèi)是需要生成Model類(lèi)的
@JsonSerializable()
class User{
User(this.name, this.email);
String name;
String email;
//不同的類(lèi)使用不同的mixin即可
factory User.fromJson(Map json) => _$UserFromJson(json);
Map toJson() => _$UserToJson(this);
} 有了這個(gè)設(shè)置,源碼生成器將生成用于序列化name和email字段的JSON代碼。
如果需要,自定義命名策略也很容易。例如,如果我們正在使用的API返回帶有_snake_case_的對(duì)象,但我們想在我們的模型中使用_lowerCamelCase_, 那么我們可以使用@JsonKey標(biāo)注:
/// Tell json_serializable that "registration_date_millis" should be
/// mapped to this property.
@JsonKey(name: 'registration_date_millis')
final int registrationDateMillis;
運(yùn)行代碼生成程序
json_serializable第一次創(chuàng)建類(lèi)時(shí),您會(huì)看到與下圖類(lèi)似的錯(cuò)誤。
這些錯(cuò)誤是完全正常的,這是因?yàn)閙odel類(lèi)的生成代碼還不存在。為了解決這個(gè)問(wèn)題,我們必須運(yùn)行代碼生成器來(lái)為我們生成序列化模板。
There are two ways of running the code generator. 有兩種運(yùn)行代碼生成器的方法:
一次性生成
通過(guò)在我們的項(xiàng)目根目錄下運(yùn)行flutter packages pub run build_runner build,我們可以在需要時(shí)為我們的model生成json序列化代碼。 這觸發(fā)了一次性構(gòu)建,它通過(guò)我們的源文件,挑選相關(guān)的并為它們生成必要的序列化代碼。
雖然這非常方便,但如果我們不需要每次在model類(lèi)中進(jìn)行更改時(shí)都要手動(dòng)運(yùn)行構(gòu)建命令的話(huà)會(huì)更好。
持續(xù)生成
使用_watcher_可以使我們的源代碼生成的過(guò)程更加方便。它會(huì)監(jiān)視我們項(xiàng)目中文件的變化,并在需要時(shí)自動(dòng)構(gòu)建必要的文件。我們可以通過(guò)flutter packages pub run build_runner watch在項(xiàng)目根目錄下運(yùn)行來(lái)啟動(dòng)_watcher_。
只需啟動(dòng)一次觀察器,然后并讓它在后臺(tái)運(yùn)行,這是安全的。
使用json_serializable模型
要通過(guò)json_serializable方式反序列化JSON字符串,我們不需要對(duì)先前的代碼進(jìn)行任何更改。
Map userMap = JSON.decode(json);
var user = new User.fromJson(userMap);
序列化也一樣。調(diào)用API與之前相同。
String json = JSON.encode(user);
有了json_serializable,我們可以在User類(lèi)上忘記任何手動(dòng)的JSON序列化 。源代碼生成器創(chuàng)建一個(gè)名為user.g.dart的文件,它具有所有必需的序列化邏輯。 現(xiàn)在,我們不必編寫(xiě)自動(dòng)化測(cè)試來(lái)確保序列化的正常工作 - 這個(gè)庫(kù)會(huì)確保序列化工作正常。
一些參考
- Json編解碼文檔
- The json_serializable package in Pub
- json_serializable examples in GitHub
- Discussion about dart:mirrors in Flutter
分享題目:創(chuàng)新互聯(lián)Flutter教程:FlutterJSON和序列化
網(wǎng)站地址:http://m.fisionsoft.com.cn/article/djpsihp.html


咨詢(xún)
建站咨詢(xún)
