Flutter解析複雜JSON泛型方案--拋磚引玉篇

liuxuzxx發表於2019-08-07

問題

最近在小試牛刀Flutter,基本搞了UI的學習和佈局,Redux的資料管理以及非同步請求,最近這兩天陷入了一個JSON解析的問題上面 ,本來,我以為很簡單,我是從Java過來的,Java已經有了各種的JSON解析jar包,好用到非常。我就想Dart是Google推出來的東西,肯定是已經完美的解決了JSON解析的各種問題,即使沒有完美解決,那肯定有工具包能解決,後來發現不是那麼回事。 下面是我的Http請求返回的結果物件

class ResponseDto{
  int code;
  String message;
  String data;

  ResponseDto({this.code, this.message, this.data});

  factory ResponseDto.fromJson(Map<String, dynamic> json) {
    return ResponseDto(
      code: json['code'],
      message: json['message'],
      data: json['data'],
    );
  }
}
複製程式碼

我的想法是,給ResponseDto一個泛型,然後用dart:convert加上json_serializable就可以順理成章的搞定了,後來發現不是那麼回事,反正是得手動,因為dart不讓你用反射. 但是在解析過程中會出現:

type 'List<dynamic>' is not a subtype of type 'List<String>'
複製程式碼

而且我這個ResponseDto的屬性data有可能是各種型別:List,Map,int,String,陣列,其他物件,反正是服務端返回的結果資料,不能定死型別,我之前的想法是用String接收,然後自己手動根據型別解釋,後面發現不得行啊。

我的解決方案

  1. 修改ResponseDto為泛型
class ResponseDto<T> {
  int code;
  String message;
  T data;

  ResponseDto({this.code, this.message, this.data});

  factory ResponseDto.fromJson(Map<String, dynamic> json) {
    return ResponseDto(
      code: json['code'],
      message: json['message'],
      data: json['data'],
    );
  }
}

ResponseDto就不要使用json_serializable配置了
複製程式碼
  1. 使用的時候
//使用Dart內建的http請求服務端資料
var response = await http.get(RemoteServerConfig.remoteRoot + "/api/rattrap/ancient-article/article-type/types");
//ResponseDto的data為List資料結構的時候,使用這個泛型型別:List<dynamic>
List<dynamic> list = ResponseDto<List<dynamic>>.fromJson(json.decode(response.body)).data);
複製程式碼

解析成自己需要的型別

class LoadChineseAncientArticleTypeAction {
  List<ChineseAncientArticleTypeDto> typeDtoList;
  LoadChineseAncientArticleTypeAction({this.typeDtoList});

  factory LoadChineseAncientArticleTypeAction.create(List<dynamic> jsonData) {
    var types = jsonData
        .map((typeJson) => ChineseAncientArticleTypeDto.fromJson(typeJson))//解析成需要的型別
        .toList();
    return LoadChineseAncientArticleTypeAction(typeDtoList: types);
  }
}

create方法傳入上面獲取到的List<dynamic>物件即可
複製程式碼

如果返回的是一個物件

var data = ResponseData<dynamic>.fromJson(json.decode(response.body)).data;

之後用你的 接收物件的fromJson方法就行了
複製程式碼

總結

注意response.body是String型別 反正感覺Dart這個json解析有點半自動的感覺,不知道後面Google會體會到開發者的訴求,放開許可權,或者提供一個解決方案,在或者提供一個現成的package那就更完美了.如果可以像Java的fastjson、Gson那樣的工具包就更加好了,開發起來輕鬆愉悅.

有一篇翻譯文章可以看下,瞭解整個json的解析問題:[譯]在 Flutter 中解析複雜的 JSON

相關文章