本文涉及的業務場景
只要我們的app不是單機的,那麼必然涉及到遠端伺服器資料請求。在flutter
中,發起請求已經有現成的包dio
了,使用起來也非常簡練方便,如還是不是很瞭解,可以點選檢視dio的詳細文件。
發起請求,拿到服務端返回的json資料後,接下來的步驟是怎麼樣的。flutter
(應該說是Dart
)可不像javascript
那樣,對json
天生友好。這就是本文要講的主要內容。
json資料讀取和處理
請求回來資料後,下一步必然就是讀取其中的資料資訊,然後依此進行介面展示和邏輯處理了。
如果返回來的是簡單的資料,而且業務邏輯也很簡單,那麼其實處理方式也可以簡單化,例如服務端返回資料如下:
{
code: 200,
message: null,
value: true
}
複製程式碼
那麼,你甚至可以這麼處理:
if (jsonStr.indexOf('true') != -1) {
// do something
}
複製程式碼
總結的說,在這種場景下面,使用正規表示式匹配或者簡單字串處理邏輯,進行簡單快速的實現,也不失為一種好方法。
json反序列化
但是,當資料結構足夠複雜(例如:點選檢視複雜資料示例),那麼上述的方式顯然就有點捉襟見肘了。
這個時候,就該輪到本文要講述的重點,json
反序列化上場了。關於序列化和反序列化,可以上網查一下,有很多資料(實在不想查,好吧,這裡有現成的,點選序列化湊合著看一下吧...)。
在本文描述的業務場景下面,也可以簡單理解為,我們要做的,就是把通過dio
拿到的服務端json
字串資料,轉換為物件,然後就可以愉快的訪問該物件中的欄位值了。
主要的步驟有兩個:
json
字串轉換為Map
物件- 使用
json_serializable
進行反序列化
具體步驟如下:
- 新增依賴
參考下面程式碼,往pubspec.yaml
檔案中新增json_annotation
、json_serializable
和build_runner
包。
dependencies:
flutter:
sdk: flutter
json_annotation: ^3.0.0
dev_dependencies:
flutter_test:
sdk: flutter
json_serializable: ^3.2.0
build_runner: ^1.6.5
複製程式碼
新增完,記得flutter packages get
- 使用線上程式碼生成工具把json生成dart程式碼,程式碼命名為
xxxx.dart
(檔案一,會在下文的程式碼中引用到)copy到專案中
如果你已經看過其他相關文章,很有可能是要你根據json
資料寫一個dart的實體類,其實,也可以的,選擇你喜歡方式就行了。本文推薦工具生成,方便快捷,不易出錯,哈哈。。。
- 在當前專案的目錄下執行
flutter packages pub run build_runner build
,命令執行完成,根據剛剛的xxxx.dart
生成xxxx.g.dart
(該檔案生成後不要手動改,也無需引用,放著不動就是了) - 開始編碼
import 'dart:convert';
import 'package:xxxxxxx/xxxx.dart'; //引入上面提及的檔案一
String jsonStr = '{"value":1}'; //你要進行反序列化的json字串
Map<String ,dynamic> map = json.decode(jsonStr); //先轉成Map
MyObject obj = MyObject.fromJson(map); //假設class名為MyObject,這個根據實際情況調整
print(obj.value);
複製程式碼
到此,基本就完成了資料的反序列化。上述程式碼中,主要是兩個步驟:
- String to Map
- Map to MyObject
MyObject
即引入的“檔案一”中的類名,可根據實際情況進行調整。
也可能你會有疑問,既然原生已經提供了String to Map
,那麼只做到這一步,然後使用map物件進行接下來的coding,ok嗎。
其實,也是可以的,只是。。。,下面舉個列子對比一下,便一目瞭然了。以該資料示例為例,下面兩行程式碼,訪問的欄位是一樣的:
print(homePageList.value[0].modules[0].items[1].title);
print(map.entries.elementAt(2).value[0].entries.elementAt(5).value[0].entries.elementAt(11).value[1].entries.elementAt(0).value);
複製程式碼
不知你喜歡哪種方式呢。。。
複雜不規則資料處理
按照上述的具體步驟,基本可以處理大部分的規則資料了,但是當你以資料示例為資料來源,一步一步操作coding完,訪問其中某些欄位的值時,意想不到的事情發生了:
print(homePageList.value[0].modules[0].items[1].title); //正常列印
print(homePageList.value[0].modules[2].items[0].name); // 報錯
複製程式碼
報錯資訊:
The following NoSuchMethodError was throw building BlockRowFrame(dirty):
Class 'Modules' has no instance getter 'title'.
...
複製程式碼
這是因為,資料每一項的結構不一致導致的。資料示例中,欄位name
在前兩個modules
的items
元素中並沒有,而在第三個modules
的items
元素中,卻有了。
遇到這種情況,只需要在用工具生成的"檔案一"中對應的class
,手動新增上對應的欄位程式碼,然後再重新執行一次flutter packages pub run build_runner build --delete-conflicting-outputs
便可。
到此,關於flutter json
資料處理分享就講完了。碼字不易,覺得此文對你有幫助的,麻煩點個贊鼓勵鼓勵。
後記
如果還有不清楚的地方。。。
沒關係,原始碼伺候,點選flutter_examples訪問對應的github專案,其中的“json格式請求結果反序列化與使用(dio & json_serializable demo)”例項,就是本文的程式碼實現!