跳到主要內容

Flutter: JSON Parser example

Flutter的Json處理真是有夠難...

看了老半天還是看不太懂, 挫折感重重.

他有兩套方法一個是dart內建的dart:convert,另一個是套件,其號稱較容易處理複雜的JSON結構.

===

一個外國網友說: 

I have to admit, I was missing the gson world of Android after working with JSON in Flutter/Dart. When I started working with APIs in Flutter, JSON parsing really had me struggle a lot. And I’m certain, it confuses a lot of you beginners.

by Pooja Bhaumik

大家可以去讀這篇json parse in flutter文章

ps:額外閱讀:30天Flutter手滑系列 - JSON與序列化(JSON and serialization)

 ---

Is there a GSON/Jackson/Moshi equivalent in Flutter?

The simple answer is no. 

似乎是因為 程式庫 反射(run-time reflection)的關係,使得Flutter 無法對其做檔案最小化.

 ----

在android我們用gson太久,太方便,所以被寵壞了.

一換到flutter後,沒有gson,我們就不會用了.

寫程式這種技能,就跟啃饅頭一樣,很簡單,但你還得一口一口慢慢啃完.

對,沒有自己寫出一段json parser範例code,你就是算不會他.

一定要自己寫出來,結果有跑出來才算,然後在熟習其用法.等到真實專案遇到了就不會害怕.

---

Flutter有內建 dart:convert library可用來parse JSON. "為較小的項目使用手動序列化數據",但這是一個很基本的library.

Basic JSON serialization in Flutter is very simple. Flutter has a built-in dart:convert library that includes a straightforward JSON encoder and decoder. 

JSON 解碼是指在 dart:convert 中使用內置的 JSON 解碼器。它包括將原始 JSON 字符串傳遞給 jsonDecode() 方法,然後在產生的 Map<String, dynamic> 計算結果中尋找你需要的值。它沒有外部依賴或者特定的設置過程,這有利於快速證明概念。

當你的項目變大時,手動解碼表現得並不理想。手動編寫解碼邏輯會變得難以管理並容易出錯。如果你產生了筆誤去獲取一個不存在的 JSON 字段,你的代碼會在運行時拋出一個錯誤。

---- 

Serializing JSON inside model classes

轉換json (json serialization) 需要建立一個model class.

這很繁瑣,以前在設計原生android時,我們不需要自己寫這model class,因為有plug-in可以自動產生.所以很快可以產生,但flutter裡有沒有?

有的:

使用代碼生成庫序列化 JSON 數據

 json_serializable,一個自動化源代碼生成器來為你生成 JSON 序列化數據模板。

寫到這我就有感而發,軟體工程師必須要專注生產,遇到這麼複雜不熟悉的工作,很容易就放棄.

一家公司,如果不重視軟體研發,視軟體研發是草芥一般的話,

工程師很容易就離職,公司所累積的技術就流失了.

----

在前景轉換Json時不能超過16ms. 否則須在背景處理.

當你需要進行一個非常複雜的計算時,例如解析一個巨大的 JSON 文件。

如果這項工作耗時超過了 16 毫秒,那麼你的用戶就會感受到停頓。16ms有多短,就是0.016 second.也就是說超級短的,因此,除非自我測試時可以容忍外,其餘轉換json的工作勢必一律都得在背景處理了.

這就要牽涉到flutter中的isolate的用法.只有將這部分-轉換json的工作移交到單獨的 isolate中,把工作放在背景執行. 所以UI就不會lag了.(在android中就是AsyncTask).

 ----

大坑:   DioError [DioErrorType.response]: XMLHttpRequest error.

不明原因遇到這問題,跟dio有關....似乎跟瀏覽器的跨域問題有關.

(現代瀏覽器支援在API 容器(如 XMLHttpRequest 或 Fetch )中使用CORS 以降低跨來源HTTP 請求的風險。

跨來源資源共用(Cross-Origin Resource Sharing (CORS))是一種使用額外 HTTP 標頭令目前瀏覽網站的使用者代理 (en-US)取得存取其他來源(網域)伺服器特定資源權限的機制。當使用者代理請求一個不是目前文件來源——例如來自於不同網域(domain)、通訊協定(protocol)或通訊埠(port)的資源時,會建立一個跨來源 HTTP 請求(cross-origin HTTP request)。舉個跨來源請求的例子:http://domain-a.com HTML 頁面裡面一個 <img> 標籤的 src 屬性 (en-US)載入來自 http://domain-b.com/image.jpg 的圖片。現今網路上許多頁面所載入的資源,如 CSS 樣式表、圖片影像、以及指令碼(script)都來自與所在位置分離的網域,如內容傳遞網路(content delivery networks, CDN)。

header "Access-Control-Allow-Origin": "*"

且同樣的只有web上跑會有問題,在android上跑就ok,可見會出錯是瀏覽器環境的設定問題,而不是code有問題.

solution:

1- Go to flutter\bin\cache and remove a file named: flutter_tools.stamp

2- Go to flutter\packages\flutter_tools\lib\src\web and open the file chrome.dart.

3- Find '--disable-extensions'

4- Add '--disable-web-security'

---------

若設定成功,dio error 執行錯誤將會不見, 在瀏覽器上取而代之的是一行警告,但這不影響執行結果.


 -----

至於如何使用 , 我的pubspec.yaml設定如下

dependencies:
flutter:
sdk: flutter

cupertino_icons: ^1.0.3
json_annotation:
json_serializable:
build_runner: ^2.0.6
dio: ^4.0.0
module:
androidX: true # Add this line.

 -----

然後其他請按照官方說明執行:

1.以json_serializable的方式創建model類

import 'package:json_annotation/json_annotation.dart';

// user.g.dart 將在我們運行生成命令後自動生成
part 'user.g.dart';

///這個標註是告訴生成器,這個類是需要生成Model類的
()

class User{
  User(this.name, this.email);

  String name;
  String email;
  //不同的類使用不同的mixin即可
  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}
 

有了這個設置,源碼生成器將生成用於序列化nameemail字段的JSON代碼。

如果需要,自定義命名策略也很容易。例如,如果我們正在使用的API返回帶有_snake_case_的對象,但我們想在我們的模型中使用_lowerCamelCase_, 那麼我們可以使用@JsonKey標註:

/// Tell json_serializable that "registration_date_millis" should be
/// mapped to this property.
(name: 'registration_date_millis')
final int registrationDateMillis; 
 
有了json_serializable,我們可以在User類上忘記任何手動的JSON序列化 。源代碼生成器創建一個名為user.g.dart的文件,它具有所有必需的序列化邏輯。

json_serializable第一次創建類時,您會看到類似的錯誤user.g.dart不存在

solution:

一次性生成:

flutter packages pub run build_runner build

通過在我們的項目根目錄下運行
我們可以為我們的model生成json序列化class.
 

持續生成

使用_watcher_可以使我們的源代碼生成的過程更加方便。它會監視我們項目中文件的變化,並在需要時自動構建必要的文件。我們可以通過

flutter packages pub run build_runner watch 

在項目根目錄下運行來啟動_watcher_。

只需啟動一次觀察器,然後並讓它在後台運行,這是安全的。

使用json_serializable模型

要通過json_serializable方式反序列化JSON字符串,我們不需要對先前的代碼進行任何更改。

Map userMap = JSON.decode(json);
var user = new User.fromJson(userMap);
這方法相對好用
import 'package:json_annotation/json_annotation.dart';

part 'car.d.dart';

@JsonSerializable()
class Car {
  String make;
  String model;
  
  // Default constructor
  Car(this.make, this.model);
  
  factory Car.fromJson(Map<String, dinamic> json) => _$CarFromJson(json);
  
  Map<String, dynamic> toJson() => _$CarToJson(this);
}
上面紅字部分是重點,是根據你的model name來設定,例如這邊的model name是Car.
後面就固定加上____FromJson(json) 與 ____toJson().
 
更多詳細介紹: https://everyday.codes/mobile/everything-you-need-to-know-about-json-in-flutter/
 

 

 

 

 


 

 

 

 

 

 

 


 

 

留言

這個網誌中的熱門文章

最爛的銀行服務-玉山銀行

今天寫信給玉山銀行,問他說能不能給予我免費跨行轉帳次數, 我是他們大客戶....常常需要轉帳跟提款.發現這樣被扣手續費很不划算. 玉山銀行的atm又很少見. 但是得到的回應是這樣: 看完這信,有回答等於沒回答,當下我就決定要轉到其他家銀行了, 只是有點麻煩,股票帳戶,外幣帳戶,黃金存摺帳戶... 玉山銀行在我家附近連一台提款機都沒有,每次都要借台新銀行或中信銀行的atm. 把錢放在這裡實在不方便,不斷被扣轉帳手續費跟提款手續費. 你看台新銀行richard給我五次免費額度. 使用其他家例如合作金庫與兆豐銀行都有台灣pay可以免手續費. 玉山銀行???? 今天開始要開始廢棄玉山銀行了.... 而且看這回信後,我也覺得玉山銀行很爛,自己不建atm,又不給客戶免費跨行提款次數,叫我跑大老遠自己搜尋ATM. 建議大家他的股票: 玉山 金控 ( 2884 ) 也不要買, 股價一定會慢慢下跌的,看他們家的服務讓客戶一個一個跑掉,就知道了 . 未來不是有很多純網銀出來嗎? 他們都會給予更多免費跨行轉帳次數. 感覺未來這種服務不佳的銀行都準備被淘汰吧. 對於app設計師來說: 這種回答也是最不佳的. 我們要對user友善點,使用者反應app會當機,有問題時, 回答要能解決他們的問題. 千萬不能像玉山銀行客服人員這樣回答. 使用者都是很厲害的,他發現你沒鳥他,明天開始就刪除app了. PS:後來去辦了兆豐銀行.行員說只要辦個數位帳戶就有10次跨行提款...而且已經有一般非數位帳戶也可再申請一個數位的. 相比玉山銀行還限制如果有玉山帳戶者再申請數位帳號也沒有跨行轉帳提款優惠,玉山真的好差... 除此之外,台新銀行也給我各5次免費跨行轉帳+提款次數 真的好好..(以上都不用薪轉戶,一般人都有資格可以申請) 有了15次轉帳跟跨行提款免費,就不用到處找ATM.... 心情好多了,現在欠缺的就是錢了

app bundle and bundletool. 關於aab安裝問題

google 有說明年開始強制使用app bundle. 不然不准更新app. 但是產出的apk不再是apk了,而是aab. C:\release>adb install 6.aab Performing Streamed Install adb.exe: filename doesn't end .apk or .apex: 6.aab   不能透過adb install.... so, google 發表一個新tool: 去download bundletool...因為是java跨平台都可執行. https://github.com/google/bundletool/releases   You can extract the apks files from the aab file using the bundletool command. https://developer.android.com/studio/command-line/bundletool To generate an APK set for all device configurations (signed with a debug key) you can use:  bundletool build-apks --bundle=/MyApp/my_app.aab --output=/MyApp/my_app.apks To deploy your app from an APK set, use the install-apks  bundletool install-apks --apks=/MyApp/my_app.apks test:   C:\release>java -jar bundletool.jar build-apks --bundle=6.aab --output=out_6.apks INFO: The APKs will be signed with the debug keystore found at 'C:\Users\mark\.android\debug.keystore'.   還是失敗,還要指定key才可以...  For Release apk command, example 1: bundle

ios app 上架時app icon要注意事項

按照apple ios app icon標準(App Icon Attributes): All app icons should adhere to the following specifications. 所有app icon須符合下列: -Format: PNG  , 一定要png...但全彩png size很大 .. -Color: 注意24bit不要有透明色在上面. -Layers: Flattened with no transparency. 絕不可以有alpha透明色. -Shape Square with no rounded corners 不可以有圓角,之後apple會統一用圓角特效上去. -Resolution: -iPhone X, iPhone 8 Plus, iPhone 7 Plus, and iPhone 6s Plus @3x -All other high-resolution iOS devices @2x ps: 建議不要使用 PDF 檔案.. pdf內是一個向量圖,本來是用來減少png的size太大問題. 但對於較複雜的圖像而言 PNG 的表現實際上是優於 PDF 的. iOS系統會自動把 30x30 的 PDF 圖檔做成 @2x 60x60 的 PNG 圖檔. 很複雜的官方說明: Image Size (px) File Name Used For App Store 512x512 iTunesArtwork App list in iTunes Do not include 1024x1024 iTunesArtwork@2x App list in iTunes on devices with retina display Do not include 120x120 (最重要!) Icon-60@2x.png Home screen on iPhone/iPod Touch with retina displ

SMR疊瓦式hdd致命缺陷被解決????!!!

新聞來源: https://tech.sina.cn/2019-12-25/detail-iihnzahi9980174.d.html 現在90%所有的硬碟 … 除了SSD 之外都是採用PMR 技術,但為容量增長而發展的SMR( 疊瓦式磁紀錄)會比較便宜不要踩地雷 。 PMR、SMR 硬碟分別是什麼? PMR (perpendicular magnetic recording,垂直磁性記錄). 寫入磁頭會比讀取磁頭來得大,因此硬碟供應商若要增加磁錄密度,就會儘可能讓寫入磁頭的尺寸縮小至物理極限為止。 SMR (shingled magnetic recording,疊瓦式磁性記錄). SMR 採用的技術是讓資料循序寫入,如其名稱所示,磁軌會如瓦片般堆疊在另一磁軌的部分面積上,藉此達到增加磁錄密度的目的。在此情況下,讀取磁頭仍可從磁軌上未被覆蓋的部分來讀取資料。   玩家對SMRHDD避之唯恐不及,因為這種HDD性能、可靠性都有問題,但它能提升HDD存儲密度大約1/4 PMR 與 SMR 的差異 當 SMR 硬碟上循序寫入新資料時,這些如瓦片般堆疊的磁軌仍可正常讀取, 並不影響讀取效能。 不過,一旦已寫入的資料要修改或覆寫時,寫入磁頭並不會直接在既有的磁軌上進行磁錄,以避免毀損相鄰的磁軌。 編輯後的資料會先在磁碟上的空白處寫入,原先舊資料的磁軌會暫時維持不動。 等到硬碟閒置時才會進行重新整理的機制,將原先磁軌上的舊資料自動清除,並重新成為可用空間以供新資料寫入。 就前述的重新整理機制而言, SMR 硬碟的閒置時間就顯得相當重要。如果 SMR 硬碟長時間進行密集的覆寫任務,則會沒有足夠的閒置時間來重新整理磁軌,暫時不動的既有資料磁軌數量會越來越多。接著導致 SMR 硬碟必須一邊寫入新資料,一邊重新整理舊磁軌,進而對讀寫效能造成某種程度的影響。 WD他們開發了名為Zonefs的文件系統,有望解決SMR HDD寫入數據時的弊端,同時也適用於SSD。 WD近年來一直在研究分區存儲(Zoned Storage),它將 HDD的LBA空間分成多個區塊,只能從每個區塊的開頭順序寫入數據,而且數據不能任意覆蓋。這種數據存儲技術可以改變SMR、SSD HDD存儲、寫入數據的方式,不會再像現在這樣有很多隨機

更改google drive預設存放目錄位置Change Google Drive Default Folder Location in Windows

Google drive預設存放位置是放在C:\Users\username\Google 雲端硬碟.有些人c槽是ssd,空間有限.如果一不小心,像google drive空間有1TB的人. SSD就被塞爆...需要改放在其他磁碟機..(例如c是ssd, D是一般硬碟..可能有幾TB) 1.如果之前已經安裝的人,首先先解除帳戶連結.解除後再刪除掉目前的舊的Google Drive 目錄.釋放已占空間.(不用擔心,因為已經備份到雲端,待會會自動再下載回來.) 2.再次登入帳戶,在最後一頁時.不要那麼快按確認,這裡有個"進階設定". 3.這邊可更改預設資料夾...我們把他改到D槽...或其他槽. 建一個新目錄,取個好記的名字,例如"[GoogleDrive]",加上特殊字元"[" "]"可讓資料夾排在最前面,將來比較好找.更改好之後,再選擇這新資料夾.   PS: 也建議大家不要把Google drive預設資料夾放在C:\Users\username\Google 雲端硬碟. 一則不方便找.二則重灌電腦時,會忘記這邊有資料,整理起來很麻煩.三是C通常是SSD,容量小,設在D槽(如果是HDD的話),可避免塞爆SSD.