最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

flutter中的JSON和序列化方法及使用詳解

 更新時間:2023年01月12日 11:34:15   作者:前端那些年  
這篇文章主要為大家介紹了flutter中的JSON和序列化方法及使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

很難想象一款移動應(yīng)用程序不需要與web服務(wù)器通信,也不需要存儲結(jié)構(gòu)化數(shù)據(jù)。在開發(fā)一款網(wǎng)絡(luò)連接的應(yīng)用程序時,它遲早會需要使用一些JSON。

這里簡單介紹一下JSON在flutter中的使用。

Tips:

編碼和序列化是將數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換為字符串的同一件事。解碼和反序列化是將字符串轉(zhuǎn)換為數(shù)據(jù)結(jié)構(gòu)的相反過程。然而,序列化通常也指將數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換為更易于閱讀的格式的整個過程。

哪種JSON序列化方法適合

這里主要簡單介紹兩種序列化方式:

  • 手動序列化
  • 使用代碼自動序列化

不同的項目復(fù)雜度以及用例都不同,對于一些較小的項目或者類似原型的的應(yīng)用,使用代碼生成可能有些大材小用,而對于有很多不同json模型的應(yīng)用程序,使用手動序列化則除了無聊之外,有可能會產(chǎn)生不必要的問題和麻煩。

手動進(jìn)行序列化

手動進(jìn)行json解碼說的是使用dart:convert內(nèi)置的json解碼器,通過將原始的json數(shù)據(jù)傳遞給jsonDecode()方法,然后在返回的Map<String, dynamic>這個類型的數(shù)據(jù)中我們可以找到我們想用的數(shù)據(jù)。不需要別的依賴和其他的設(shè)置過程,對于驗證一些快速的原型或者小型的項目非常有效。

當(dāng)項目逐漸變的越來越大的時候,手動解碼可能會表現(xiàn)的不盡人意。手動編寫解碼邏輯可能會變得越來越難以管理,而且變得非常容易出錯,如果訪問到不存在的字段,或者編寫時有拼寫錯誤,代碼在運(yùn)行時就會發(fā)生錯誤。

使用代碼自動序列化

對于中大型項目來說,使用代碼自動進(jìn)行序列化可能會是一個比較不錯的選擇,意味著我們可以使用外部的依賴庫來生成我們想要的模版。我們通過設(shè)置一些初始化的配置,然后運(yùn)行一個file watcher從我們的模型類中生成我們想要的代碼數(shù)據(jù)。

比如我們可以使用:json_serializable或者build_value諸如之類的庫。

這種方法適用于更大的項目。不需要手工編寫模版,并且在編譯時會捕捉到訪問JSON字段時的拼寫錯誤。

代碼生成的缺點是需要一些初始設(shè)置。另外,生成的源文件可能會在項目導(dǎo)航器中產(chǎn)生視覺上的混亂。

Flutter 中是否有 GSON/Jackson/Moshi 之類的序列化類庫?

GSON以及Jackson都是 Java中用來序列化json的類庫。

Moshi則是Kotlin中用來序列化json的類庫。

事實上Flutter中并沒有類似的庫。

因為,這樣的庫需要使用運(yùn)行時反射,這在Flutter中是禁用的。運(yùn)行時反射會干擾【樹抖動】treeShaking,Dart已經(jīng)支持了很長時間。通過treeShaking樹抖動,您可以從發(fā)布版本中“抖掉”未使用的代碼,這可以優(yōu)化應(yīng)用程序的大小。

由于反射默認(rèn)情況下會隱式使用所有代碼,因此很難進(jìn)行treeShaking樹抖動。這些工具無法知道哪些部分在運(yùn)行時未使用,因此冗余代碼很難去除。使用反射時,無法輕松優(yōu)化應(yīng)用程序大小。

雖然我們不能在Flutter中使用運(yùn)行時反射,但有些庫提供了類似的API,是基于代碼生成。

使用dart:convert內(nèi)置庫手動進(jìn)行序列化

Flutter中的基本JSON序列化非常簡單。Flutter有一個內(nèi)置的dart:convert庫,其中包含一個簡單的JSON編碼器和解碼器。

看下面的示例:

{
  "name": "John Smith",
  "email": "john@example.com"
}

使用dart:convert庫,我們有兩種方法進(jìn)行序列化。

調(diào)用jsonDecode()方法:

Map<String, dynamic> user = jsonDecode(jsonString);
print('Howdy, ${user['name']}!');
print('We sent the verification link to ${user['email']}.');

但是需要注意的是,jsonDecode()方法會返回一個類型為Map<String, dynamic>的類型,這樣的話,我們就特別需要注意json中字段的各種類型。

在模型類中序列化JSON

此外,我們可以引入一個簡單的模型類(在本例中稱為User)來解決前面提到的問題。在User類中,我們可以發(fā)現(xiàn):

  • User.fromJson()構(gòu)造函數(shù),用于從Map構(gòu)造新的User實例。
  • toJson()方法,將User實例轉(zhuǎn)換為Map。

使用這種方法,調(diào)用代碼時可以具有類型安全及編譯時異常提醒。如果我們輸入了錯別字,或者將字段視為int而不是String,應(yīng)用程序?qū)⒉粫幾g,而不會在運(yùn)行時崩潰。

// 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)在轉(zhuǎn)移到模型本身內(nèi)部。使用這種新方法,您可以輕松地解碼User:

Map<String, dynamic> userMap = jsonDecode(jsonString);
var user = User.fromJson(userMap);
print('Howdy, ${user.name}!');
print('We sent the verification link to ${user.email}.');

和解碼(Decode)相反的是編碼(Encode),如果我們想要對User進(jìn)行編碼,我們可以使用jsonEncode()方法:

String json = jsonEncode(user);

使用這種方法,調(diào)用代碼根本不必?fù)?dān)心JSON序列化。然而,模型類仍然必須這樣做。在生產(chǎn)應(yīng)用程序中,我們需要確保序列化工作正常進(jìn)行。在實際開發(fā)過程中,User.fromJson()User.toJson()方法可能都需要進(jìn)行單元測試以保證結(jié)果的正確性。

使用序列化庫

盡管有其他庫可用,但是這里使用了json_serializable,這是一個自動源代碼生成器,可為我們生成json序列化模版。

要在項目中包含json_serializable,需要一個常規(guī)依賴項和兩個開發(fā)依賴項。簡而言之,開發(fā)依賴項是不包含在我們的應(yīng)用程序源代碼中的依賴項,它們只在開發(fā)環(huán)境中使用。

我們需要在pubspec.yaml進(jìn)行如下配置:

**pubspec.yaml**
dependencies:
  # Your other regular dependencies here
  json_annotation: <latest_version>
dev_dependencies:
  # Your other dev_dependencies here
  build_runner: <latest_version>
  json_serializable: <latest_version>

然后在項目根文件夾中運(yùn)行flutter pub-get以安裝依賴。

然后我們以json_serializable的方式創(chuàng)建模型類:

// user.dart
import 'package:json_annotation/json_annotation.dart';
/// This allows the `User` class to access private members in
/// the generated file. The value for this is *.g.dart, where
/// the star denotes the source file name.
part 'user.g.dart';
/// An annotation for the code generator to know that this class needs the
/// JSON serialization logic to be generated.
@JsonSerializable()
class User {
  User(this.name, this.email);
  String name;
  String email;
  /// A necessary factory constructor for creating a new User instance
  /// from a map. Pass the map to the generated `_$UserFromJson()` constructor.
  /// The constructor is named after the source class, in this case, User.
  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  /// `toJson` is the convention for a class to declare support for serialization
  /// to JSON. The implementation simply calls the private, generated
  /// helper method `_$UserToJson`.
  Map<String, dynamic> toJson() => _$UserToJson(this);
}

通過這種設(shè)置,源代碼生成器生成用于對JSON中的nameemail字段進(jìn)行編碼和解碼的代碼。

如果需要的話,我們還可以定制命名策略,比如,如果API返回帶有的對象帶有snake_case屬性,并且我們希望在模型中使用lowerCamelCase,則可以使用帶有name參數(shù)的@JsonKey注釋:

/// Tell json_serializable that "registration_date_millis" should be
/// mapped to this property.
@JsonKey(name: 'registration_date_millis')
final int registrationDateMillis;

服務(wù)器和客戶端最好都遵循相同的命名策略。

@JsonSerializable()提供了fieldRename的枚舉,用于將dart字段完全轉(zhuǎn)換為JSON鍵。

修改@JsonSerializable(fieldRename:fieldRename.sake)相當(dāng)于向每個字段添加@JsonKey(name:“<snake_case>”)。

服務(wù)器返回的數(shù)據(jù)是不確定的,所以有必要驗證和保護(hù)客戶端上的數(shù)據(jù)。

其他常用的@JsonKey注釋包括:

/// Tell json_serializable to use "defaultValue" if the JSON doesn't
/// contain this key or if the value is `null`.
@JsonKey(defaultValue: false)
final bool isAdult;
/// When `true` tell json_serializable that JSON must contain the key, 
/// If the key doesn't exist, an exception is thrown.
@JsonKey(required: true)
final String id;
/// When `true` tell json_serializable that generated code should 
/// ignore this field completely. 
@JsonKey(ignore: true)
final String verificationCode;

運(yùn)行代碼生成實用程序

當(dāng)?shù)谝淮蝿?chuàng)建json_serializable類時,會出現(xiàn)類似下圖所示的錯誤。

這些錯誤完全是正常的,只是因為為模型類生成的代碼還不存在。要解決此問題,我們需要運(yùn)行生成序列化樣板的代碼生成器。

運(yùn)行代碼生成器有兩種方法。

  • 一次性代碼生成
  • 持續(xù)生成代碼

一次性代碼生成

通過在項目根目錄中運(yùn)行

flutter pub run build_runner build --delete-conflicting-outputs

我們可以在需要時為模型生成JSON序列化代碼。這將觸發(fā)一次性構(gòu)建,該構(gòu)建將遍歷源文件,選擇相關(guān)文件,并為它們生成必要的序列化代碼。

雖然這很方便,但如果我們不必每次在模型類中進(jìn)行更改時都手動運(yùn)行構(gòu)建,那就更好了。

持續(xù)生成代碼

觀察者模式使我們的源代碼生成過程更加方便。它監(jiān)聽項目文件中的更改,并在需要時自動生成必要的文件。 通過在項目根目錄中運(yùn)行

flutter pub run build_runner watch --delete-conflicting-outputs

可以安全地啟動一次觀察程序,并讓它在一直后臺運(yùn)行。

使用json_serializable模型

要以JSON_serializable的方式解碼JSON字符串,實際上不需要對我們之前的代碼進(jìn)行任何更改。

Map<String, dynamic> userMap = jsonDecode(jsonString);
var user = User.fromJson(userMap);

編碼也是如此。調(diào)用API與之前相同。

String json = jsonEncode(user);

使用json_serializable,我們可以放棄User類中的任何手動json序列化。源代碼生成器創(chuàng)建一個名為user.g.dart的文件,該文件具有所有必要的序列化邏輯。我們不再需要編寫自動化測試來確保序列化工作,現(xiàn)在庫負(fù)責(zé)確保序列化工作正常。

ps:這里所說的解碼和編碼,對應(yīng)的是DecodeEncode

以上就是flutter中的JSON和序列化方法及使用詳解的詳細(xì)內(nèi)容,更多關(guān)于flutter JSON序列化的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Android之Gallery使用例子

    Android之Gallery使用例子

    本篇文章主要介紹了Android之Gallery使用例子,Gallery用來顯示圖片列表,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-01-01
  • Android仿微信右上角點擊加號彈出PopupWindow

    Android仿微信右上角點擊加號彈出PopupWindow

    這篇文章主要為大家詳細(xì)介紹了Android仿微信右上角點擊加號彈出PopupWindow,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-04-04
  • RecyclerView實現(xiàn)縱向和橫向滾動

    RecyclerView實現(xiàn)縱向和橫向滾動

    這篇文章主要為大家詳細(xì)介紹了RecyclerView實現(xiàn)縱向和橫向滾動,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • WheelView實現(xiàn)上下滑動選擇器

    WheelView實現(xiàn)上下滑動選擇器

    這篇文章主要為大家詳細(xì)介紹了WheelView實現(xiàn)上下滑動選擇器的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • Android編程實現(xiàn)ActionBar的home圖標(biāo)動畫切換效果

    Android編程實現(xiàn)ActionBar的home圖標(biāo)動畫切換效果

    這篇文章主要介紹了Android編程實現(xiàn)ActionBar的home圖標(biāo)動畫切換效果,涉及Android布局、樣式、Activity及菜單相關(guān)操作技巧,需要的朋友可以參考下
    2017-01-01
  • Android BindService使用案例講解

    Android BindService使用案例講解

    這篇文章主要介紹了Android BindService使用案例講解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Android自定義Drawable之在Drawable中部指定透明區(qū)域方法示例

    Android自定義Drawable之在Drawable中部指定透明區(qū)域方法示例

    對于不同的屏幕密度、不同的設(shè)備方向,不同的語言和區(qū)域,都會涉及到備選 drawable 資源,下面這篇文章主要給你大家介紹了關(guān)于Android自定義Drawable之在Drawable中部指定透明區(qū)域的相關(guān)資料,需要的朋友可以參考下
    2018-07-07
  • 詳解Android中Application設(shè)置全局變量以及傳值

    詳解Android中Application設(shè)置全局變量以及傳值

    這篇文章主要介紹了詳解Android中Application設(shè)置全局變量以及傳值的相關(guān)資料,希望通過本文大家能夠理解掌握這部分內(nèi)容,需要的朋友可以參考下
    2017-09-09
  • 解決android studio引用遠(yuǎn)程倉庫下載慢(JCenter下載慢)

    解決android studio引用遠(yuǎn)程倉庫下載慢(JCenter下載慢)

    這篇文章主要介紹了解決android studio引用遠(yuǎn)程倉庫下載慢(JCenter下載慢),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • 如何在Android App中集成支付寶和微信支付功能

    如何在Android App中集成支付寶和微信支付功能

    支付是各位Android開發(fā)者們在日常工作中經(jīng)常會遇到的一個需求,下面這篇文章主要給大家介紹了關(guān)于如何在Android App中集成支付寶和微信支付功能的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-05-05

最新評論

镇江市| 高淳县| 达州市| 兴海县| 托克托县| 辽阳县| 莱阳市| 昔阳县| 寿光市| 铜陵市| 海宁市| 和静县| 雷波县| 启东市| 理塘县| 营口市| 德阳市| 赤峰市| 綦江县| 木兰县| 富源县| 静安区| 会理县| 怀柔区| 淄博市| 陆河县| 县级市| 中卫市| 开平市| 贵州省| 嘉义市| 永年县| 威宁| 西乌珠穆沁旗| 沂南县| 尼勒克县| 海盐县| 梨树县| 林口县| 界首市| 绥芬河市|