為您解碼網(wǎng)站建設(shè)的點(diǎn)點(diǎn)滴滴
發(fā)表日期:2018-11 文章編輯:小燈 瀏覽次數(shù):1921
很難想象一個(gè)移動(dòng)應(yīng)用程序不需要與Web服務(wù)器通信或在某些時(shí)候容易存儲(chǔ)結(jié)構(gòu)化數(shù)據(jù)。制作網(wǎng)絡(luò)連接的應(yīng)用程序時(shí),遲早需要消耗一些好的舊JSON。
本指南介紹了如何在Flutter中使用JSON。它涵蓋了在不同場(chǎng)景中使用哪種JSON解決方案,以及原因。
本文介紹了使用JSON的兩種常規(guī)策略:
不同的項(xiàng)目具有不同的復(fù)雜性和用例。對(duì)于較小的概念驗(yàn)證項(xiàng)目或快速原型,使用代碼生成器可能過度。對(duì)于具有更多復(fù)雜性的多個(gè)JSON模型的應(yīng)用程序,手動(dòng)編碼很快就會(huì)變得乏味,重復(fù),并且適用于許多小錯(cuò)誤。
手動(dòng)JSON解碼是指使用內(nèi)置的JSON解碼器 dart:convert
。它涉及將原始JSON字符串傳遞給json.decode()
方法,然后Map<String, dynamic>
在方法返回時(shí)查找所需的值。它沒有外部依賴性或特定的設(shè)置過程,它有利于快速驗(yàn)證概念。
當(dāng)項(xiàng)目變大時(shí),手動(dòng)解碼效果不佳。手動(dòng)編寫解碼邏輯可能變得難以管理且容易出錯(cuò)。如果在訪問不存在的JSON字段時(shí)出現(xiàn)拼寫錯(cuò)誤,則代碼會(huì)在運(yùn)行時(shí)拋出錯(cuò)誤。
如果您的項(xiàng)目中沒有很多JSON模型,并且希望快速測(cè)試概念,那么手動(dòng)序列化可能就是您想要的方式。有關(guān)手動(dòng)編碼的示例,請(qǐng)參閱 使用dart:convert手動(dòng)序列化JSON。
使用代碼生成的JSON序列化意味著使用外部庫為您生成編碼樣板。進(jìn)行一些初始設(shè)置后,您將運(yùn)行一個(gè)文件監(jiān)視器,從您的模型類生成代碼。例如, json_serializable和 built_value 就是這些類型的庫。
這種方法適用于較大的項(xiàng)目。不需要手寫的樣板文件,并且在編譯時(shí)捕獲訪問JSON字段時(shí)的拼寫錯(cuò)誤。代碼生成的缺點(diǎn)是它需要一些初始設(shè)置。此外,生成的源文件可能會(huì)在項(xiàng)目導(dǎo)航器中產(chǎn)生視覺混亂。
當(dāng)您擁有中型或大型項(xiàng)目時(shí),您可能希望使用生成的代碼進(jìn)行JSON序列化。要查看基于JSON編碼的代碼生成示例,請(qǐng)參閱 使用代碼生成庫序列化JSON。
簡(jiǎn)單回答是不。
這樣的庫需要使用運(yùn)行時(shí)反射,這在Flutter中被禁用。運(yùn)行時(shí)反射會(huì)干擾樹抖動(dòng),Dart已經(jīng)支持了很長時(shí)間。在樹搖動(dòng)的情況下,您可以從發(fā)布版本中“擺脫”未使用的代碼。這顯著優(yōu)化了應(yīng)用程序的大小。
由于反射使得默認(rèn)情況下隱式使用所有代碼,因此使樹難以振動(dòng)。這些工具無法知道運(yùn)行時(shí)哪些部分未使用,因此冗余代碼很難剝離。使用反射時(shí),應(yīng)用程序大小無法輕松優(yōu)化。
** dartson怎么樣?**
該dartson庫使用運(yùn)行時(shí)反射,這使得它不兼容flutter。
雖然您不能在Flutter中使用運(yùn)行時(shí)反射,但是某些庫為您提供了類似的易用API,而是基于代碼生成。代碼生成庫部分更詳細(xì)地介紹了此方法。
Flutter中的基本JSON編碼非常簡(jiǎn)單。Flutter有一個(gè)內(nèi)置 dart:convert
庫,包括一個(gè)簡(jiǎn)單的JSON編碼器和解碼器。
以下是簡(jiǎn)單用戶模型的示例JSON。
{ "name": "John Smith", "email": "john@example.com" }
有了dart:convert
,您可以通過兩種方式對(duì)此JSON模型進(jìn)行編碼。
通過查看dart:轉(zhuǎn)換JSON文檔,您將看到可以通過調(diào)用json.decode
方法解碼JSON ,并使用JSON字符串作為方法參數(shù)。
Map<String, dynamic> user = json.decode(json);print('Howdy, ${user['name']}!'); print('We sent the verification link to ${user['email']}.');
不幸的是,json.decode()
只返回a Map<String, dynamic>
,這意味著在運(yùn)行時(shí)之前您不知道值的類型。使用這種方法,您將丟失大多數(shù)靜態(tài)類型語言功能:類型安全性,自動(dòng)完成以及最重要的編譯時(shí)異常。您的代碼將立即變得更容易出錯(cuò)。
例如,無論何時(shí)訪問name
或email
字段,都可能會(huì)快速引入拼寫錯(cuò)誤。由于JSON存在于地圖結(jié)構(gòu)中,編譯器不知道的拼寫錯(cuò)誤。
通過引入User
在此示例中調(diào)用的普通模型類來對(duì)抗前面提到的問題。在User
課堂上,你會(huì)發(fā)現(xiàn):
User.fromJson
構(gòu)造函數(shù),構(gòu)造一個(gè)新的User
從地圖結(jié)構(gòu)實(shí)例。toJson
將User
實(shí)例轉(zhuǎn)換為地圖的方法。使用這種方法,調(diào)用代碼可以具有類型安全性,name
和email
字段的自動(dòng)完成以及編譯時(shí)異常。如果您使用拼寫錯(cuò)誤或?qū)⒆侄我暈?code>ints而不是String
s,則應(yīng)用程序?qū)o法編譯,而不是在運(yùn)行時(shí)崩潰。
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, }; }
解碼邏輯的責(zé)任現(xiàn)在在模型本身內(nèi)部移動(dòng)。使用這種新方法,您可以輕松解碼用戶。
Map userMap = json.decode(json); var user = new User.fromJson(userMap);print('Howdy, ${user.name}!'); print('We sent the verification link to ${user.email}.');
要對(duì)用戶進(jìn)行編碼,請(qǐng)將User
對(duì)象傳遞給json.encode
方法。您不需要調(diào)用該toJson
方法,因?yàn)?code>json.encode 已經(jīng)為您完成了。
String json = json.encode(user);
使用這種方法,調(diào)用代碼根本不必?fù)?dān)心JSON序列化。但是,模型類仍然必須。在生產(chǎn)應(yīng)用程序中,您需要確保序列化正常工作。在實(shí)踐中,這些User.fromJson
和User.toJson
方法都需要進(jìn)行單元測(cè)試以驗(yàn)證正確的行為。
但是,現(xiàn)實(shí)場(chǎng)景通常不那么簡(jiǎn)單。您不太可能使用如此小的JSON響應(yīng)。嵌套的JSON對(duì)象也是常用的。
如果有一些東西可以為您處理JSON編碼和解碼,那就太好了。幸運(yùn)的是,有!
雖然還有其他庫可用,但本指南使用 json_serializable包,這是一個(gè)自動(dòng)生成的源代碼生成器,可為您生成JSON序列化樣板。
由于序列化代碼不再是手動(dòng)或手動(dòng)維護(hù)的,因此可以最大限度地降低在運(yùn)行時(shí)出現(xiàn)JSON序列化異常的風(fēng)險(xiǎn)。
要包含json_serializable
在項(xiàng)目中,您需要一個(gè)常規(guī)依賴項(xiàng)和兩個(gè)dev依賴項(xiàng)。簡(jiǎn)而言之,dev依賴項(xiàng) 是我們的應(yīng)用程序源代碼中未包含的依賴項(xiàng) - 它們僅在開發(fā)環(huán)境中使用。
可以通過遵循 JSON可序列化示例中的pubspec文件來查看這些必需依賴項(xiàng)的最新版本 。
pubspec.yaml
dependencies: # Your other regular dependencies here json_annotation: ^2.0.0dev_dependencies: # Your other dev_dependencies here build_runner: ^1.0.0 json_serializable: ^2.0.0
flutter packages get
在項(xiàng)目根文件夾中運(yùn)行(或單擊 編輯器中的Packages Get)以在項(xiàng)目中使用這些新的依賴項(xiàng)。
以json_serializable方式創(chuàng)建模型類
以下顯示如何將User類轉(zhuǎn)換為一個(gè)類json_serializable 。為簡(jiǎn)單起見,此代碼使用先前示例中的簡(jiǎn)化JSON模型。
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, }; }
采用這種設(shè)置,源代碼生成器用于編碼和將編碼生成代碼name
和email
從JSON字段。
如果需要,還可以輕松自定義命名策略。例如,如果API返回帶有snake_case的對(duì)象,并且您想在模型中使用 lowerCamelCase,則可以使用@JsonKey
帶有name參數(shù)的注釋:
/// Tell json_serializable that "registration_date_millis" should be /// mapped to this property. @JsonKey(name: 'registration_date_millis') final int registrationDateMillis;
json_serializable
第一次創(chuàng)建類時(shí),您將收到類似于下圖所示的錯(cuò)誤。
這些錯(cuò)誤完全正常,僅僅是因?yàn)槟P皖惖纳纱a尚不存在。要解決此問題,請(qǐng)運(yùn)行生成序列化樣板的代碼生成器。
有兩種運(yùn)行代碼生成器的方法。
通過flutter packages pub run build_runner build
在項(xiàng)目根目錄中運(yùn)行,可以在需要時(shí)為模型生成JSON序列化代碼。這會(huì)觸發(fā)一次性構(gòu)建,該構(gòu)建遍歷源文件,選擇相關(guān)文件,并為它們生成必要的序列化代碼。
雖然這很方便,但如果您不必每次在模型類中進(jìn)行更改時(shí)都必須手動(dòng)運(yùn)行構(gòu)建,那將是很好的。
一個(gè)觀察者,使我們的源代碼生成的過程更加方便。它會(huì)監(jiān)視項(xiàng)目文件中的更改,并在需要時(shí)自動(dòng)構(gòu)建必要的文件。通過flutter packages pub run build_runner watch
在項(xiàng)目根目錄中運(yùn)行來啟動(dòng)觀察程序 。
啟動(dòng)觀察者一次并讓它在后臺(tái)運(yùn)行是安全的。
要以這種json_serializable
方式解碼JSON字符串,您實(shí)際上沒有對(duì)我們以前的代碼進(jìn)行任何更改。
Map userMap = json.decode(json); var user = User.fromJson(userMap);
編碼也是如此。調(diào)用API與以前相同。
String json = json.encode(user);
有了json_serializable
,您可以忘記User
該類中的任何手動(dòng)JSON序列化 。源代碼生成器創(chuàng)建一個(gè)名為的文件user.g.dart
,該文件具有所有必需的序列化邏輯。您不再需要編寫自動(dòng)化測(cè)試來確保序列化工作 - 現(xiàn)在圖書館有責(zé)任確保序列化正常工作。
有關(guān)更多信息,請(qǐng)參閱以下資源: