You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter无法访问REST API返回对象数组字段的问题排查

解决Flutter中访问REST API返回字段的报错问题

从REST API获取对象数组后,在Flutter中访问posts、comments、likes和status字段时失败,报错:The getter 'data' isn't defined for the type 'List',错误出现在代码行snapshot.data!.data[index].posts[postPosition].url和snapshot.data!.data[index].status。

问题根源

  1. snapshot.data本身就是List<Posts>类型,无需额外调用.data属性,多写的这层调用直接导致报错
  2. Post类字段名不匹配:API返回的图片地址字段是post,代码中错误使用了.url
  3. Posts类中多余的data和length getter完全无用,反而造成混淆
  4. 嵌套ListView未处理滚动冲突,会导致界面滚动异常

API返回数据

[
    {
        "_id": "6304e73ecdc5d350cc33e902",
        "userId": "6304e42231ef2e7a4dec924d",
        "posts": [
            {
                "postType": "image",
                "post": "https://www.theskinnybeep.com/wp-content/uploads/2019/01/Versace-Man-2019.jpg",
                "_id": "6304e73ecdc5d350cc33e903"
            },
            {
                "postType": "image",
                "post": "https://www.theskinnybeep.com/wp-content/uploads/2019/01/Versace-Man-2019.jpg",
                "_id": "6304e73ecdc5d350cc33e904"
            }
        ],
        "status": "testing status",
        "comments": [
            {
                "commentText": "Testing comment",
                "commentAt": "2022-08-23T14:41:55.646Z",
                "commentReplys": [
                    {
                        "userId": "6304e02d481e08d44e618d41",
                        "replyText": "Testing comment",
                        "replyAt": "2022-08-23T14:41:55.646Z",
                        "replyLikes": [
                            {
                                "userId": "6304e02d481e08d44e618d41",
                                "_id": "6304e73ecdc5d350cc33e907",
                                "isNotified": true
                            },
                            {
                                "userId": "6304e42231ef2e7a4dec924d",
                                "isNotified": true,
                                "_id": "6305f8d07d513ce62b9c099f"
                            }
                        ],
                        "_id": "6304e73ecdc5d350cc33e906"
                    },
                    {
                        "userId": "6304e02d481e08d44e618d41",
                        "replyText": "reply text testing",
                        "replyAt": "2022-08-23T15:57:51.259Z",
                        "_id": "6304f90191c32e0deac663b8",
                        "replyLikes": [
                            {
                                "userId": "6304e42231ef2e7a4dec924d",
                                "isNotified": true,
                                "_id": "6305f8d07d513ce62b9c099f"
                            }
                        ]
                    }
                ],
                "commentLikes": [
                    {
                        "userId": "6304e42231ef2e7a4dec924d",
                        "isNotified": true,
                        "_id": "6305f8f67d513ce62b9c09a2"
                    }
                ],
                "commentId": "bc174de0-22f1-11ed-9c5d-23d89a83ff32",
                "_id": "6304e73ecdc5d350cc33e905"
            },
            {
                "commentText": "Testing comment",
                "commentAt": "2022-08-23T15:02:11.123Z",
                "commentId": "90928740-22f4-11ed-b912-e99836187b6d",
                "_id": "6304ec67825b5926f0f074cf",
                "commentReplys": [
                    {
                        "userId": "6304e02d481e08d44e618d41",
                        "replyText": "reply text testing",
                        "replyAt": "2022-08-23T15:57:51.259Z",
                        "_id": "6304f90191c32e0deac663b8",
                        "replyLikes": [
                            {
                                "userId": "6304e42231ef2e7a4dec924d",
                                "isNotified": true,
                                "_id": "6305f8d07d513ce62b9c099f"
                            }
                        ]
                    }
                ],
                "commentLikes": [
                    {
                        "userId": "6304e42231ef2e7a4dec924d",
                        "isNotified": true,
                        "_id": "6305f8f67d513ce62b9c09a2"
                    }
                ]
            },
            {
                "commentText": "Testing comment",
                "commentAt": "2022-08-23T15:02:11.123Z",
                "commentId": "90928740-22f4-11ed-b912-e99836187b6d",
                "_id": "6304ec81825b5926f0f074d1",
                "commentReplys": [
                    {
                        "userId": "6304e02d481e08d44e618d41",
                        "replyText": "reply text testing",
                        "replyAt": "2022-08-23T15:57:51.259Z",
                        "_id": "6304f90191c32e0deac663b8",
                        "replyLikes": [
                            {
                                "userId": "6304e42231ef2e7a4dec924d",
                                "isNotified": true,
                                "_id": "6305f8d07d513ce62b9c099f"
                            }
                        ]
                    }
                ],
                "commentLikes": [
                    {
                        "userId": "6304e42231ef2e7a4dec924d",
                        "isNotified": true,
                        "_id": "6305f8f67d513ce62b9c09a2"
                    }
                ]
            }
        ],
        "likes": [
            {
                "userId": "6304e42231ef2e7a4dec924d",
                "_id": "63052dc7a1728d463769681b"
            }
        ],
        "__v": 0
    },
    {
        "_id": "63070a03584ed0febe5b5a5f",
        "status": "testing",
        "posts": [],
        "comments": [],
        "likes": []
    }
]

修正后的Flutter代码

Widget build(BuildContext context) {
  return SizedBox(
    height: 600,
    child: FutureBuilder<List<Posts>>(
      future: fetchPost(),
      builder: ((context, snapshot) {
        if (snapshot.hasData) {
          return ListView.builder(
            scrollDirection: Axis.vertical,
            shrinkWrap: true,
            itemCount: snapshot.data!.length,
            itemBuilder: (context, index) {
              final postItem = snapshot.data![index];
              return Column(
                children: [
                  Text(postItem.status ?? ''),
                  if (postItem.posts.isNotEmpty)
                    ListView.builder(
                      scrollDirection: Axis.vertical,
                      shrinkWrap: true,
                      physics: const NeverScrollableScrollPhysics(), // 解决嵌套滚动冲突
                      itemCount: postItem.posts.length,
                      itemBuilder: (context, postPosition) {
                        final singlePost = postItem.posts[postPosition];
                        return Image.network(singlePost.post ?? '');
                      },
                    ),
                ],
              );
            },
          );
        } else {
          return const CircularProgressIndicator();
        }
      }),
    ),
  );
}

修正后的Posts及关联类

import 'dart:convert';
import 'dart:core';

List<Posts> postsFromJson(String str) => List<Posts>.from(json.decode(str).map((x) => Posts.fromJson(x)));

String postsToJson(List<Posts> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

class Posts {
  Posts({
    this.id,
    this.userId,
    required this.posts,
    this.status,
    this.comments,
    this.likes,
  });

  String? id;
  String? userId;
  List<Post> posts;
  String? status;
  List<Comment>? comments;
  List<Like>? likes;

  factory Posts.fromJson(Map<String, dynamic> json) => Posts(
        id: json["_id"],
        userId: json["userId"],
        posts: List<Post>.from(json["posts"].map((x) => Post.fromJson(x))),
        status: json["status"],
        comments: json["comments"] != null 
            ? List<Comment>.from(json["comments"].map((x) => Comment.fromJson(x)))
            : null,
        likes: json["likes"] != null
            ? List<Like>.from(json["likes"].map((x) => Like.fromJson(x)))
            : null,
      );

  Map<String, dynamic> toJson() => {
        "_id": id,
        "userId": userId,
        "posts": List<dynamic>.from(posts.map((x) => x.toJson())),
        "status": status,
        "comments": comments != null ? List<dynamic>.from(comments!.map((x) => x.toJson())) : null,
        "likes": likes != null ? List<dynamic>.from(likes!.map((x) => x.toJson())) : null,
      };
}

class Post {
  Post({
    this.postType,
    this.post,
    this.id,
  });

  String? postType;
  String? post;
  String? id;

  factory Post.fromJson(Map<String, dynamic> json) => Post(
        postType: json["postType"],
        post: json["post"],
        id: json["_id"],
      );

  Map<String, dynamic> toJson() => {
        "postType": postType,
        "post": post,
        "_id": id,
      };
}

class Comment {
  Comment({
    this.commentText,
    this.commentAt,
    this.commentReplys,
    this.commentLikes,
    this.commentId,
    this.id,
  });

  String? commentText;
  DateTime? commentAt;
  List<CommentReply>? commentReplys;
  List<Like>? commentLikes;
  String? commentId;
  String? id;

  factory Comment.fromJson(Map<String, dynamic> json) => Comment(
        commentText: json["commentText"],
        commentAt: DateTime.parse(json["commentAt"]),
        commentReplys: json["commentReplys"] != null
            ? List<CommentReply>.from(json["commentReplys"].map((x) => CommentReply.fromJson(x)))
            : null,
        commentLikes: json["commentLikes"] != null
            ? List<Like>.from(json["commentLikes"].map((x) => Like.fromJson(x)))
            : null,
        commentId: json["commentId"],
        id: json["_id"],
      );

  Map<String, dynamic> toJson() => {
        "commentText": commentText,
        "commentAt": commentAt?.toIso8601String(),
        "commentReplys": commentReplys != null ? List<dynamic>.from(commentReplys!.map((x) => x.toJson())) : null,
        "commentLikes": commentLikes != null ? List<dynamic>.from(commentLikes!.map((x) => x.toJson())) : null,
        "commentId": commentId,
        "_id": id,
      };
}

class CommentReply {
  CommentReply({
    this.userId,
    this.replyText,
    this.replyAt,
    this.replyLikes,
    this.id,
  });

  String? userId;
  String? replyText;
  DateTime? replyAt;
  List<Like>? replyLikes;
  String? id;

  factory CommentReply.fromJson(Map<String, dynamic> json) => CommentReply(
        userId: json["userId"],
        replyText: json["replyText"],
        replyAt: DateTime.parse(json["replyAt"]),
        replyLikes: json["replyLikes"] != null
            ? List<Like>.from(json["replyLikes"].map((x) => Like.fromJson(x)))
            : null,
        id: json["_id"],
      );

  Map<String, dynamic> toJson() => {
        "userId": userId,
        "replyText": replyText,
        "replyAt": replyAt?.toIso8601String(),
        "replyLikes": replyLikes != null ? List<dynamic>.from(replyLikes!.map((x) => x.toJson())) : null,
        "_id": id,
      };
}

class Like {
  Like({
    this.userId,
    this.id,
    this.isNotified,
  });

  String? userId;
  String? id;
  bool? isNotified;

  factory Like.fromJson(Map<String, dynamic> json) => Like(
        userId: json["userId"],
        id: json["_id"],
        isNotified: json["isNotified"],
      );

  Map<String, dynamic> toJson() => {
        "userId": userId,
        "_id": id,
        "isNotified": isNotified,
      };
}

关键修正说明

  1. 移除多余的.data调用:snapshot.data!直接是List<Posts>,通过[index]即可获取单个Posts对象
  2. 匹配字段名:将代码中访问图片地址的.url改为API返回的.post
  3. 清理无用代码:删除Posts类中无意义的data和length getter
  4. 解决滚动冲突:给嵌套的ListView添加NeverScrollableScrollPhysics(),避免滚动手势冲突
  5. 空值安全处理:对可能为null的字段添加空值判断,防止运行时异常

内容的提问来源于stack exchange,提问作者Jeevan Shrestha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 22:54:34