flutter json資料處理

ShellHong發表於2019-08-26

本文涉及的業務場景

只要我們的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_annotationjson_serializablebuild_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'.
...
複製程式碼

The following NoSuchMethodError was throw building BlockRowFrame(dirty)

這是因為,資料每一項的結構不一致導致的。資料示例中,欄位name在前兩個modulesitems元素中並沒有,而在第三個modulesitems元素中,卻有了。

遇到這種情況,只需要在用工具生成的"檔案一"中對應的class,手動新增上對應的欄位程式碼,然後再重新執行一次flutter packages pub run build_runner build --delete-conflicting-outputs便可。

到此,關於flutter json資料處理分享就講完了。碼字不易,覺得此文對你有幫助的,麻煩點個贊鼓勵鼓勵。

後記

如果還有不清楚的地方。。。

沒關係,原始碼伺候,點選flutter_examples訪問對應的github專案,其中的“json格式請求結果反序列化與使用(dio & json_serializable demo)”例項,就是本文的程式碼實現!

相關文章