欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

引言

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

這里簡(jiǎn)單介紹一下JSON在flutter中的使用。

Tips:

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

哪種JSON序列化方法適合

這里主要簡(jiǎn)單介紹兩種序列化方式:

  • 手動(dòng)序列化
  • 使用代碼自動(dòng)序列化

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

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

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

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

使用代碼自動(dòng)序列化

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

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

這種方法適用于更大的項(xiàng)目。不需要手工編寫模版,并且在編譯時(shí)會(huì)捕捉到訪問JSON字段時(shí)的拼寫錯(cuò)誤。

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

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

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

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

事實(shí)上Flutter中并沒有類似的庫。

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

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

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

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

Flutter中的基本JSON序列化非常簡(jiǎn)單。Flutter有一個(gè)內(nèi)置的dart:convert庫,其中包含一個(gè)簡(jiǎn)單的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()方法會(huì)返回一個(gè)類型為Map<String, dynamic>的類型,這樣的話,我們就特別需要注意json中字段的各種類型。

在模型類中序列化JSON

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

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

使用這種方法,調(diào)用代碼時(shí)可以具有類型安全及編譯時(shí)異常提醒。如果我們輸入了錯(cuò)別字,或者將字段視為int而不是String,應(yīng)用程序?qū)⒉粫?huì)編譯,而不會(huì)在運(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)在轉(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),如果我們想要對(duì)User進(jìn)行編碼,我們可以使用jsonEncode()方法:

String json = jsonEncode(user);

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

使用序列化庫

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

要在項(xiàng)目中包含json_serializable,需要一個(gè)常規(guī)依賴項(xiàng)和兩個(gè)開發(fā)依賴項(xiàng)。簡(jiǎn)而言之,開發(fā)依賴項(xiàng)是不包含在我們的應(yīng)用程序源代碼中的依賴項(xià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>

然后在項(xiàng)目根文件夾中運(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è)置,源代碼生成器生成用于對(duì)JSON中的nameemail字段進(jìn)行編碼和解碼的代碼。

如果需要的話,我們還可以定制命名策略,比如,如果API返回帶有的對(duì)象帶有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)于向每個(gè)字段添加@JsonKey(name:“<snake_case>”)。

服務(wù)器返回的數(shù)據(jù)是不確定的,所以有必要驗(yàn)證和保護(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)行代碼生成實(shí)用程序

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

這些錯(cuò)誤完全是正常的,只是因?yàn)闉槟P皖惿傻拇a還不存在。要解決此問題,我們需要運(yùn)行生成序列化樣板的代碼生成器。

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

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

一次性代碼生成

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

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

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

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

持續(xù)生成代碼

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

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

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

使用json_serializable模型

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

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

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

String json = jsonEncode(user);

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

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

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

相關(guān)文章

  • Android編程圖片加載類ImageLoader定義與用法實(shí)例分析

    Android編程圖片加載類ImageLoader定義與用法實(shí)例分析

    這篇文章主要介紹了Android編程圖片加載類ImageLoader定義與用法,結(jié)合實(shí)例形式分析了Android圖片加載類ImageLoader的功能、定義、使用方法及相關(guān)操作注意事項(xiàng),代碼中備有較為詳盡的注釋便于理解,需要的朋友可以參考下
    2017-12-12
  • Flutter使用JsBridge方式處理Webview與H5通信的方法

    Flutter使用JsBridge方式處理Webview與H5通信的方法

    這篇文章主要介紹了Flutter使用JsBridge方式處理Webview與H5通信的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • Android使用RecycleView實(shí)現(xiàn)拖拽交換item位置

    Android使用RecycleView實(shí)現(xiàn)拖拽交換item位置

    這篇文章主要為大家詳細(xì)介紹了Android使用RecycleView實(shí)現(xiàn)拖拽交換item位置,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • RxJava 1升級(jí)到RxJava 2過程中踩過的一些“坑”

    RxJava 1升級(jí)到RxJava 2過程中踩過的一些“坑”

    RxJava2相比RxJava1,它的改動(dòng)還是很大的,那么下面這篇文章主要給大家總結(jié)了在RxJava 1升級(jí)到RxJava 2過程中踩過的一些“坑”,文中介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下來要一起看看吧。
    2017-05-05
  • Android實(shí)現(xiàn)通用篩選欄

    Android實(shí)現(xiàn)通用篩選欄

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)通用篩選欄,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • Android自定義View實(shí)現(xiàn)柱狀波形圖的繪制

    Android自定義View實(shí)現(xiàn)柱狀波形圖的繪制

    柱狀波形圖是一種常見的圖形。一個(gè)個(gè)柱子按順序排列,構(gòu)成一個(gè)波形圖。本文將利用Android自定義View實(shí)現(xiàn)柱狀波形圖的繪制,需要的可以參考一下
    2022-08-08
  • Android 照相機(jī)的實(shí)例應(yīng)用

    Android 照相機(jī)的實(shí)例應(yīng)用

    這篇文章主要介紹了Android 照相機(jī)的實(shí)例應(yīng)用的相關(guān)資料,希望通過此文能掌握Android照相機(jī)的使用方法,需要的朋友可以參考下
    2017-08-08
  • Android使用 Spinner控件實(shí)現(xiàn)下拉框功能

    Android使用 Spinner控件實(shí)現(xiàn)下拉框功能

    Spinner是android的一種控件,用它我們可以實(shí)現(xiàn)下拉框。下面通過實(shí)例代碼給大家介紹Android使用 Spinner控件實(shí)現(xiàn)下拉框功能,感興趣的朋友一起看看吧
    2018-08-08
  • Android Internet應(yīng)用實(shí)現(xiàn)獲取天氣預(yù)報(bào)的示例代碼

    Android Internet應(yīng)用實(shí)現(xiàn)獲取天氣預(yù)報(bào)的示例代碼

    這篇文章主要介紹了Android網(wǎng)絡(luò)編程及Internet應(yīng)用-獲取天氣,小編覺得挺不錯(cuò)的,一起跟隨小編過來看看吧
    2018-05-05
  • Android開發(fā)之DialogFragment用法實(shí)例總結(jié)

    Android開發(fā)之DialogFragment用法實(shí)例總結(jié)

    這篇文章主要介紹了Android開發(fā)之DialogFragment用法,結(jié)合實(shí)例形式總結(jié)分析了Android使用DialogFragment代替Dialog功能的相關(guān)使用技巧與注意事項(xiàng),需要的朋友可以參考下
    2017-11-11

最新評(píng)論