如何从列表中映射 Flutter JSON 字符串?

Posted

技术标签:

【中文标题】如何从列表中映射 Flutter JSON 字符串?【英文标题】:How to Map Flutter JSON Strings from List? 【发布时间】:2018-02-24 01:20:05 【问题描述】:

我成功地将我的响应打印为来自我的 YouTube JSON url 的字符串,但是当我尝试通过“项目”进行序列化时,我收到以下错误 Unhandled exception: type 'List' is not a subtype of type 'Map' of 'json' where List is from dart:core Map is from dart:core

这是我的代码...

class CardInfo 
  //Constructor
  String id;
  String description;
  String role;
  //int score;

  CardInfo.fromJson(Map json) 
    this.id = json['vieoId'];
    this.description = json['description'];
    this.role = json['title'];
    //this.score = json['score'];
  


Future getData() async 
    String url = 'YouTube url';
    var httpClient  = createHttpClient();
    var response = await httpClient.get(url);
    Map data = JSON.decode(response.body);
    //String ip = data['items'];
    var ci = new CardInfo.fromJson(data['items']);

    //print(data['items']);
    print(ci.id);
    //print(ci.description);
    //print(ci.role);

    if (!mounted) return;


    setState(() );

  

print(data['items'] 正在打印,但print(ci.id) 或任何 Card Info 变量都会引发上述错误。

****print(data)的日志;

kind: youtube#searchListResponse, etag: "VPWTmrH7dFmi4s1RqrK4tLejnRI/P9wyOxsXEuXOCvj7znCun2-EykU", nextPageToken: CAMQAA, regionCode: US, pageInfo: totalResults: 1000000, resultsPerPage: 3, items: [kind: youtube#searchResult, etag: "VPWTmrH7dFmi4s1RqrK4tLejnRI/Csl1kQhnOsbs0j4_336zJAN176k", id: kind: youtube#video, videoId: e3pUxU_bE6w, snippet: publishedAt: 2017-09-14T09:43:17.000Z, channelId: UCbD8EppRX3ZwJSou-TVo90A, title: [PRISTIN - We Like] KPOP TV Show | M COUNTDOWN 170914 EP.541, description: KPOP Chart Show M COUNTDOWN | EP.541 - PRISTIN - We Like ▷Watch more video clips: http://MCOUNTDOWN-KPOP2017 [Kor Ver.] 프리티 ..., thumbnails: default: url: https://i.ytimg.com/vi/e3pUxU_bE6w/default.jpg, width: 120, height: 90, medium: url: https://i.ytimg.com/vi/e3pUxU_bE6w/mqdefault.jpg, width: 320, height: 180, high: url: https://i.ytimg.com/vi/e3pUxU_bE6w/hqdefault.jpg, width: 480, height: 360, channelTitle: Mnet K-POP, liveBroadcastContent: none, kind: youtube#searchResult, etag: "VPWTmrH7dFmi4s1RqrK4tLejnRI/1JCCNBPNbFeusCp_9-pl4i8q5OU", id: kind: youtube#video, videoId: Cc4hO9RLdl4, snippet: publishedAt: 2017-09-14T10:37:29.000Z, channelId: UCbD8EppRX3ZwJSou-TVo90A, title: [EXO - Power] KPOP TV Show | M COUNTDOWN 170914 EP.541, description: KPOP Chart Show M COUNTDOWN | EP.541 - EXO - Power ▷Watch more video clips: http://MCOUNTDOWN-KPOP2017 [Kor Ver.] Power Up! '#EXO' 여기 ..., thumbnails: default: url: https://i.ytimg.com/vi/Cc4hO9RLdl4/default.jpg, width: 120, height: 90, medium: url: https://i.ytimg.com/vi/Cc4hO9RLdl4/mqdefault.jpg, width: 320, height: 180, high: url: https://i.ytimg.com/vi/Cc4hO9RLdl4/hqdefault.jpg, width: 480, height: 360, channelTitle: Mnet K-POP, liveBroadcastContent: none, kind: youtube#searchResult, etag: "VPWTmrH7dFmi4s1RqrK4tLejnRI/ZnYC4e5evyfldkM67HsDuV8Yh3E", id: kind: youtube#video, videoId: BBcOM25wrVo, snippet: publishedAt: 2017-08-18T15:21:48.000Z, channelId: UCtFtO4By4czgkYGvEXvJu0A, title: Kpop Banned Dance: MV vs LIVE, description: Kpop Banned Dance: MV vs LIVE Koreas biggest broadcasting companies has strict rules and standards on what lyrics and dances moves can be performed., thumbnails: default: url: https://i.ytimg.com/vi/BBcOM25wrVo/default.jpg, width: 120, height: 90, medium: url: https://i.ytimg.com/vi/BBcOM25wrVo/mqdefault.jpg, width: 320, height: 180, high: url: https://i.ytimg.com/vi/BBcOM25wrVo/hqdefault.jpg, width: 480, height: 360, channelTitle: Kpop Corn, liveBroadcastContent: none]

*** 用 FOR 循环语句更新

这是我的 for loop 的代码,它返回 type 'String' is not a subtype of type 'int' of 'index' 错误...

Map data = JSON.decode(response);
var videos = data['items'];
for (var items in videos['snippet'])
      print(items);
    

通过items in videos 循环运行,为我正在寻找的 3 个视频提供了 3 个单独的条目 - 包括 sn-ps。尝试获取单个 sn-ps 失败。请指出我正确的方向。

【问题讨论】:

我相信你正在传递key "items"value,从外观上看它实际上是List 而不是Map,你的构造函数应该收到一个@ 987654336@,但您传递的是List。因此,您会收到错误消息。否则,你能告诉我 print(data) 看看你的数据库是如何构建的吗? @aziza 感谢您的以下课程。地图 = NSDictionary 和列表​​ = NSArray。我注意到有一个 itariter 来遍历一个列表。我现在正在阅读有关这些的文档。我在我的问题中添加了print(data)。请帮助获取标题、videoId、描述和“中等”缩略图网址的地图。谢谢。 据我所知,您正在尝试访问 snippet 的值 items。因此,您需要逐个索引遍历 data['items'] 索引,然后检查何时到达“sn-p”键,并将此特定映射传递给您的类构造函数。 @aziza 试图查看items 以访问我的snippets 时抛出了上述错误。请查看。 【参考方案1】:

看起来 data['items']List(即 JSON 数组),而不是 Map

您可以在这里使用列表理解方法来提供帮助:

final items = (data['items'] as List).map((i) => new CardInfo.fromJson(i));
for (final item in items) 
  print(item.id);

【讨论】:

'data[items]' 也是一个列表,或者 SWIFT 将其称为字典。我可以使用 for 语句以相同的方式遍历 'item' 吗? @CharlesJr 这不是真的,DictionaryList 不同。它们是两个不同的集合。实际上,Dictionary 实际上是Map。请阅读我对该问题的评论并尝试检查print (data['items']),您会发现您的物品价值实际上是MapList,类似于此'items': [..:..,..:......] @matanlurey 我的for loop 有问题。请查看我更新的问题并将其添加到您的答案中。 @matanlurey 我的物品里面还有另一个数组。 'items': ['SubItem':[ ],'SubItem':[ ]....] 我应该如何处理这种情况 我最后使用了 .toList() 来正确填充列表小部件。【参考方案2】:

以下行为您提供 itemsList

var videos = data['items'];

你会因为这条线而得到错误

for(var items in videos['snippet'])

在上一行中,您认为您正在迭代 snippet 中的数据,而实际上,您正在尝试迭代视频列表中的索引“sn-p”,这没有意义,因为迭代在任何列表上发生使用整数值videos[0] , videos [1], videos [2] .. 当你传递一个String 'snippet'

您首先需要逐项迭代您的videos 列表(每个项目都是一个地图)。将每个 Map 存储在一个变量中。那么你可以通过myMap['snippet']访问snippet的值

    Map data = JSON.decode(response);
    var videos = data['items']; //returns a List of Maps
    for (var items in videos) //iterate over the list
    Map myMap = items; //store each map 
    print(myMap['snippet']);
        

看看这是否能解决你的问题。

【讨论】:

太棒了!现在我有 3 个单独的 sn-ps,我假设我可以在我的 Card 小部件上运行类似的地图和索引。我相信您有一个类似的 SO 问题,我可以从中得出结论。 是的,您现在可以将 sn-p 传递给您的类构造函数,您可能希望首先将它们的数据存储在循环之外。很高兴它对你有用。 我相信这个what you are looking for @CharlesJr 我已经添加了有关您为什么会收到此错误的更多详细信息。【参考方案3】:

我很乐意分享这个,一些专家也可以改进这个代码,经过很多小时的战斗。

模型类

class Testimony
    String fullname;
   String testimony;

   Testimony(this.fullname,
     this.testimony); 

    factory Testimony.fromJson(Map<String, dynamic> json) => new Testimony(
      fullname: json['fullname'] as String,
       testimony: json['testimony'] as String,  
         );

         

API 类

List<Testimony> ToListandMap (String responseBody) 
 Map data = json.decode(responseBody);
    var videos = data['testimonies']; //returns a List of Maps
  final casting =  videos.cast<Map<String, dynamic>>();
   return casting.map<Testimony>((json) => Testimony.fromJson(json)).toList();
    

Future<List<Testimony>> fetchTestimonies(http.Client client) async 
       final response = await client.get('https://tryjambcbt.com/api/testimonies');

         return ToList(response.body);
         

用于 UI 的 MainWidget

FutureBuilder<List<Testimony>>(
    future: fetchTestimonies(http.Client()),
    builder: (context, snapshot) 
      if (snapshot.hasError) print(snapshot.error);
      return snapshot.hasData
          ? TestimonyList(testimony: snapshot.data)
          : Center(child: CircularProgressIndicator());
    ,
  ),

小部件

class TestimonyList extends StatelessWidget 
final List<Testimony> testimony;

TestimonyList(Key key, this.testimony) : super(key: key);

  @override
 Widget build(BuildContext context) 
  return ListView.builder(
    physics: BouncingScrollPhysics(),
    padding: EdgeInsets.only(bottom: 10),
    shrinkWrap: true,
    scrollDirection: Axis.vertical,
    itemCount: testimony.length,
    itemBuilder: (context, index) 
    return Padding(
      padding: EdgeInsets.only(right: 10),
      child: Text(testimony[index].testimony)
       );
      ,
    );
   
  

【讨论】:

以上是关于如何从列表中映射 Flutter JSON 字符串?的主要内容,如果未能解决你的问题,请参考以下文章

Flutter:如何映射嵌套的 json 对象

Flutter:将 JSON 映射到对象列表中返回 null

如何创建一个 Flutter Futurebuilder 函数来显示从 JSON 中获取的字符串数组?

Flutter:如何从 JSON 创建收藏夹列表

Flutter 从列表中获取所有数据到 json

Firebase Documentsnapshot 映射到 Flutter 中的 Json 对象