RangeError (index): Invalid value: Valid value range is empty: 0 嵌套 Json in Flutter

RangeError (index): Invalid value: Valid value range is empty: 0 Nested Json in Flutter

我正在尝试使用 flutter_bloc 库模式获取 api,我成功地获取了数据,但问题在下面,我首先提到了 json 数据两个元素在 restaurant_branch 中有一个空的 [] 数组,最后一个(第三个)元素在 restaurant_branch 中有数据,这导致空点异常 ("RangeError (index): Invalid value: Valid HomePage.dart(在文本小部件中)代码中的值范围为空:0")。那么如何防止这个问题。

json data

{
    "message": "restaurants returned",
    "data": [
        {
            "id": 40,
            "name": "Arnulfo",
            "aboutUs": "Voluptate omnis consequatur saepe doloribus tempore quia error. Praesentium esse blanditiis illo eos qui et deserunt rerum. Velit provident aliquam eveniet qui corporis. Culpa molestiae incidunt eaque unde id tempore. Tenetur ducimus amet hic sunt et.",
            "phoneNumber": 58432,
            "address": "70990 Stark Streets",
            "latitude": "73.6105",
            "longitude": "-95.9985",
            "image": "https://cdn.fakercloud.com/avatars/matthewkay__128.jpg",
            "countryCode": "VE                                                                                                                                                                                                                                                             ",
            "restaurantRegisterDocument": "Est qui voluptatem.",
            "isDeleted": false,
            "createdAt": "2021-09-04T20:24:06.310Z",
            "updatedAt": "2021-09-04T20:24:06.310Z",
            "restaurantTypeId": 1,
            "categoryId": 1,
            "userId": 3,
            "user": {
                "id": 3,
                "firstName": "Marisa",
                "lastName": "Mills",
                "email": "Darrick_Reichert94@gmail.com",
                "phoneNumber": "90428",
                "address": "870 Guadalupe River",
                "gender": "female",
                "language": "ar",
                "createdAt": "2021-09-04T20:14:05.939Z",
                "updatedAt": "2021-09-04T20:14:05.939Z"
            },
            "restaurant_branch": []
        },
        {
            "id": 39,
            "name": "Maynard",
            "aboutUs": "Sunt veniam numquam perferendis consequatur. Accusantium mollitia nemo odit nihil alias dolor. Voluptatibus officia consectetur nihil. Voluptas eligendi aliquam.",
            "phoneNumber": 93756,
            "address": "38743 Freda Green",
            "latitude": "-50.3143",
            "longitude": "114.4596",
            "image": "https://cdn.fakercloud.com/avatars/omnizya_128.jpg",
            "countryCode": "PH                                                                                                                                                                                                                                                             ",
            "restaurantRegisterDocument": "Voluptatem et expedita rerum eos eaque nihil et culpa.",
            "isDeleted": false,
            "createdAt": "2021-09-04T20:24:06.309Z",
            "updatedAt": "2021-09-04T20:24:06.309Z",
            "restaurantTypeId": 1,
            "categoryId": 4,
            "userId": 6,
            "user": {
                "id": 6,
                "firstName": "Layne",
                "lastName": "Turcotte",
                "email": "Jayson_Rice@yahoo.com",
                "phoneNumber": "98802",
                "address": "659 Trudie Keys",
                "gender": "male",
                "language": "ar",
                "createdAt": "2021-09-04T20:14:05.939Z",
                "updatedAt": "2021-09-04T20:14:05.939Z"
            },
            "restaurant_branch": []
        },
{
            "id": 10,
            "name": "Kaden",
            "aboutUs": "Et dolore cumque et iusto vel qui iste facere. Quia sed minima. Porro eos inventore qui voluptas animi voluptates fuga commodi magnam. Voluptas eligendi sunt et fugiat repudiandae asperiores maxime sit. Impedit exercitationem laudantium error autem modi voluptas et. Vitae ut non voluptatem culpa eos quae occaecati.",
            "phoneNumber": 94005,
            "address": "920 Sawayn Street",
            "latitude": "-69.1354",
            "longitude": "-176.2695",
            "image": "https://cdn.fakercloud.com/avatars/daniloc_128.jpg",
            "countryCode": "PW                                                                                                                                                                                                                                                             ",
            "restaurantRegisterDocument": "Fugiat ut autem et voluptates aut quisquam distinctio qui aut.",
            "isDeleted": true,
            "createdAt": "2021-09-04T20:14:06.352Z",
            "updatedAt": "2021-09-04T20:14:06.352Z",
            "restaurantTypeId": 6,
            "categoryId": 3,
            "userId": 4,
            "user": {
                "id": 4,
                "firstName": "Santiago",
                "lastName": "Kling",
                "email": "Yoshiko.Block@yahoo.com",
                "phoneNumber": "4436",
                "address": "809 Earlene Square",
                "gender": "female",
                "language": "ar",
                "createdAt": "2021-09-04T20:14:05.939Z",
                "updatedAt": "2021-09-04T20:14:05.939Z"
            },
            "restaurant_branch": [
                {
                    "id": 4,
                    "name": "Audreanne",
                    "description": "Kreiger",
                    "email": "Waylon.Osinski@yahoo.com",
                    "phoneNumber": 95645,
                    "address": "91601 Clifford Bypass",
                    "country_code": "SM                       ",
                    "image": "https://cdn.fakercloud.com/avatars/nicolasfolliot_128.jpg",
                    "latitude": "-42.0925",
                    "longitude": "-111.4455",
                    "workingHours": "Carolina AI Fresh",
                    "workingDays": "Friday",
                    "offDays": "Thursday",
                    "locationAddress": "802 Hoppe Ranch",
                    "locationCity": "Diamond Bar",
                    "status": 2,
                    "hasParking": true,
                    "instruction": "Bogan",
                    "isActive": true,
                    "isDeleted": false,
                    "createdAt": "2021-09-04T20:14:07.204Z",
                    "updatedAt": "2021-09-04T20:14:07.204Z",
                    "restaurantId": 10,
                    "cityId": 6,
                    "districtId": 1,
                    "feedbacks": [
                        {
                            "id": 39,
                            "comment": "International Communications Officer",
                            "star": 3,
                            "createdAt": "2021-09-04T20:24:07.433Z",
                            "updatedAt": "2021-09-04T20:24:07.433Z",
                            "customerId": 1,
                            "restaurantBranchId": 4
                        }
                    ]
                },
    ]
}

RecommendedForYouModel

class RecommendedForYouDataRestaurantBranchFeedbacks {
  int? id;
  String? comment;
  int? star;
  String? createdAt;
  String? updatedAt;
  int? customerId;
  int? restaurantBranchId;

  RecommendedForYouDataRestaurantBranchFeedbacks({
    this.id,
    this.comment,
    this.star,
    this.createdAt,
    this.updatedAt,
    this.customerId,
    this.restaurantBranchId,
  });
  RecommendedForYouDataRestaurantBranchFeedbacks.fromJson(
      Map<String, dynamic> json) {
    id = json["id"]?.toInt();
    comment = json["comment"]?.toString();
    star = json["star"]?.toInt();
    createdAt = json["createdAt"]?.toString();
    updatedAt = json["updatedAt"]?.toString();
    customerId = json["customerId"]?.toInt();
    restaurantBranchId = json["restaurantBranchId"]?.toInt();
  }
  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = Map<String, dynamic>();
    data["id"] = id;
    data["comment"] = comment;
    data["star"] = star;
    data["createdAt"] = createdAt;
    data["updatedAt"] = updatedAt;
    data["customerId"] = customerId;
    data["restaurantBranchId"] = restaurantBranchId;
    return data;
  }
}

class RecommendedForYouDataRestaurantBranch {
  int? id;
  String? name;
  String? description;
  String? email;
  int? phoneNumber;
  String? address;
  String? countryCode;
  String? image;
  String? latitude;
  String? longitude;
  String? workingHours;
  String? workingDays;
  String? offDays;
  String? locationAddress;
  String? locationCity;
  int? status;
  bool? hasParking;
  String? instruction;
  bool? isActive;
  bool? isDeleted;
  String? createdAt;
  String? updatedAt;
  int? restaurantId;
  int? cityId;
  int? districtId;
  List<RecommendedForYouDataRestaurantBranchFeedbacks?>? feedbacks;

  RecommendedForYouDataRestaurantBranch({
    this.id,
    this.name,
    this.description,
    this.email,
    this.phoneNumber,
    this.address,
    this.countryCode,
    this.image,
    this.latitude,
    this.longitude,
    this.workingHours,
    this.workingDays,
    this.offDays,
    this.locationAddress,
    this.locationCity,
    this.status,
    this.hasParking,
    this.instruction,
    this.isActive,
    this.isDeleted,
    this.createdAt,
    this.updatedAt,
    this.restaurantId,
    this.cityId,
    this.districtId,
    this.feedbacks,
  });
  RecommendedForYouDataRestaurantBranch.fromJson(Map<String, dynamic> json) {
    id = json["id"]?.toInt();
    name = json["name"]?.toString();
    description = json["description"]?.toString();
    email = json["email"]?.toString();
    phoneNumber = json["phoneNumber"]?.toInt();
    address = json["address"]?.toString();
    countryCode = json["country_code"]?.toString();
    image = json["image"]?.toString();
    latitude = json["latitude"]?.toString();
    longitude = json["longitude"]?.toString();
    workingHours = json["workingHours"]?.toString();
    workingDays = json["workingDays"]?.toString();
    offDays = json["offDays"]?.toString();
    locationAddress = json["locationAddress"]?.toString();
    locationCity = json["locationCity"]?.toString();
    status = json["status"]?.toInt();
    hasParking = json["hasParking"];
    instruction = json["instruction"]?.toString();
    isActive = json["isActive"];
    isDeleted = json["isDeleted"];
    createdAt = json["createdAt"]?.toString();
    updatedAt = json["updatedAt"]?.toString();
    restaurantId = json["restaurantId"]?.toInt();
    cityId = json["cityId"]?.toInt();
    districtId = json["districtId"]?.toInt();
    if (json["feedbacks"] != null) {
      final v = json["feedbacks"];
      final arr0 = <RecommendedForYouDataRestaurantBranchFeedbacks>[];
      v.forEach((v) {
        arr0.add(RecommendedForYouDataRestaurantBranchFeedbacks.fromJson(v));
      });
      feedbacks = arr0;
    }
  }
  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = Map<String, dynamic>();
    data["id"] = id;
    data["name"] = name;
    data["description"] = description;
    data["email"] = email;
    data["phoneNumber"] = phoneNumber;
    data["address"] = address;
    data["country_code"] = countryCode;
    data["image"] = image;
    data["latitude"] = latitude;
    data["longitude"] = longitude;
    data["workingHours"] = workingHours;
    data["workingDays"] = workingDays;
    data["offDays"] = offDays;
    data["locationAddress"] = locationAddress;
    data["locationCity"] = locationCity;
    data["status"] = status;
    data["hasParking"] = hasParking;
    data["instruction"] = instruction;
    data["isActive"] = isActive;
    data["isDeleted"] = isDeleted;
    data["createdAt"] = createdAt;
    data["updatedAt"] = updatedAt;
    data["restaurantId"] = restaurantId;
    data["cityId"] = cityId;
    data["districtId"] = districtId;
    if (feedbacks != null) {
      final v = feedbacks;
      final arr0 = [];
      v!.forEach((v) {
        arr0.add(v!.toJson());
      });
      data["feedbacks"] = arr0;
    }
    return data;
  }
}

class RecommendedForYouDataUser {
  int? id;
  String? firstName;
  String? lastName;
  String? email;
  String? phoneNumber;
  String? address;
  String? gender;
  String? language;
  String? createdAt;
  String? updatedAt;

  RecommendedForYouDataUser({
    this.id,
    this.firstName,
    this.lastName,
    this.email,
    this.phoneNumber,
    this.address,
    this.gender,
    this.language,
    this.createdAt,
    this.updatedAt,
  });
  RecommendedForYouDataUser.fromJson(Map<String, dynamic> json) {
    id = json["id"]?.toInt();
    firstName = json["firstName"]?.toString();
    lastName = json["lastName"]?.toString();
    email = json["email"]?.toString();
    phoneNumber = json["phoneNumber"]?.toString();
    address = json["address"]?.toString();
    gender = json["gender"]?.toString();
    language = json["language"]?.toString();
    createdAt = json["createdAt"]?.toString();
    updatedAt = json["updatedAt"]?.toString();
  }
  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = Map<String, dynamic>();
    data["id"] = id;
    data["firstName"] = firstName;
    data["lastName"] = lastName;
    data["email"] = email;
    data["phoneNumber"] = phoneNumber;
    data["address"] = address;
    data["gender"] = gender;
    data["language"] = language;
    data["createdAt"] = createdAt;
    data["updatedAt"] = updatedAt;
    return data;
  }
}

class RecommendedForYouData {
  int? id;
  String? name;
  String? aboutUs;
  int? phoneNumber;
  String? address;
  String? latitude;
  String? longitude;
  String? image;
  String? countryCode;
  String? restaurantRegisterDocument;
  bool? isDeleted;
  String? createdAt;
  String? updatedAt;
  int? restaurantTypeId;
  int? categoryId;
  int? userId;
  RecommendedForYouDataUser? user;
  List<RecommendedForYouDataRestaurantBranch?>? restaurantBranch;

  RecommendedForYouData({
    this.id,
    this.name,
    this.aboutUs,
    this.phoneNumber,
    this.address,
    this.latitude,
    this.longitude,
    this.image,
    this.countryCode,
    this.restaurantRegisterDocument,
    this.isDeleted,
    this.createdAt,
    this.updatedAt,
    this.restaurantTypeId,
    this.categoryId,
    this.userId,
    this.user,
    this.restaurantBranch,
  });
  RecommendedForYouData.fromJson(Map<String, dynamic> json) {
    id = json["id"]?.toInt();
    name = json["name"]?.toString();
    aboutUs = json["aboutUs"]?.toString();
    phoneNumber = json["phoneNumber"]?.toInt();
    address = json["address"]?.toString();
    latitude = json["latitude"]?.toString();
    longitude = json["longitude"]?.toString();
    image = json["image"]?.toString();
    countryCode = json["countryCode"]?.toString();
    restaurantRegisterDocument = json["restaurantRegisterDocument"]?.toString();
    isDeleted = json["isDeleted"];
    createdAt = json["createdAt"]?.toString();
    updatedAt = json["updatedAt"]?.toString();
    restaurantTypeId = json["restaurantTypeId"]?.toInt();
    categoryId = json["categoryId"]?.toInt();
    userId = json["userId"]?.toInt();
    user = (json["user"] != null)
        ? RecommendedForYouDataUser.fromJson(json["user"])
        : null;
    if (json["restaurant_branch"] != null) {
      final v = json["restaurant_branch"];
      final arr0 = <RecommendedForYouDataRestaurantBranch>[];
      v.forEach((v) {
        arr0.add(RecommendedForYouDataRestaurantBranch.fromJson(v));
      });
      restaurantBranch = arr0;
    }
  }
  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = Map<String, dynamic>();
    data["id"] = id;
    data["name"] = name;
    data["aboutUs"] = aboutUs;
    data["phoneNumber"] = phoneNumber;
    data["address"] = address;
    data["latitude"] = latitude;
    data["longitude"] = longitude;
    data["image"] = image;
    data["countryCode"] = countryCode;
    data["restaurantRegisterDocument"] = restaurantRegisterDocument;
    data["isDeleted"] = isDeleted;
    data["createdAt"] = createdAt;
    data["updatedAt"] = updatedAt;
    data["restaurantTypeId"] = restaurantTypeId;
    data["categoryId"] = categoryId;
    data["userId"] = userId;
    if (user != null) {
      data["user"] = user!.toJson();
    }
    if (restaurantBranch != null) {
      final v = restaurantBranch;
      final arr0 = [];
      v!.forEach((v) {
        arr0.add(v!.toJson());
      });
      data["restaurant_branch"] = arr0;
    }
    return data;
  }
}

class RecommendedForYou {
  String? message;
  List<RecommendedForYouData?>? data;

  RecommendedForYou({
    this.message,
    this.data,
  });
  RecommendedForYou.fromJson(Map<String, dynamic> json) {
    message = json["message"]?.toString();
    if (json["data"] != null) {
      final v = json["data"];
      final arr0 = <RecommendedForYouData>[];
      v.forEach((v) {
        arr0.add(RecommendedForYouData.fromJson(v));
      });
      this.data = arr0;
    }
  }
  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = Map<String, dynamic>();
    data["message"] = message;
    if (this.data != null) {
      final v = this.data;
      final arr0 = [];
      v!.forEach((v) {
        arr0.add(v!.toJson());
      });
      data["data"] = arr0;
    }
    return data;
  }
}

HomePage.dart

Container(
                child: Padding(
                  padding:
                      const EdgeInsets.only(top: 20.0, left: 20.0, right: 20.0),
                  child: Container(
                    height: height,
                    child: BlocBuilder<RecommendedBloc, RecommendedState>(
                        builder: (context, state) {
                      if (state is LoadingRecommendedState) {
                        return Center(
                            child: PlatformCircularProgressIndicator());
                      } else if (state is LoadedRecommendedForYouState) {
                        return buildRecommendationRestaurant(state.data);
                      } else if (state is ErrorRecommendedState) {
                        return Center(child: Text(state.message));
                      }
                      return Container();
                    }),
                  ),
                ),
              ),
  Widget buildRecommendationRestaurant(List<RecommendedForYouData> data) {
    return ListView.builder(
        shrinkWrap: true,
        scrollDirection: Axis.vertical,
        itemCount: data.length,
        itemBuilder: (BuildContext context, int index) {
          return GestureDetector(
            child: Padding(
              padding: const EdgeInsets.only(top: 10.0),
              child: Card(
                  elevation: 0,
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(10.0),
                  ),
                  child: Padding(
                    padding: const EdgeInsets.all(10.0),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.end,
                      children: [
                        Padding(
                          padding: const EdgeInsets.only(top: 5.0, right: 5.0),
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.end,
                            children: [
                              Icon(
                                Icons.near_me,
                                size: 10.0,
                              ),
                              Padding(
                                padding: const EdgeInsets.only(left: 5.0),
                                child: Text(
                                  '5km',
                                  style: TextStyle(fontSize: 10.0),
                                ),
                              ),
                            ],
                          ),
                        ),
                        Padding(
                          padding: const EdgeInsets.only(top: 5.0),
                          child: Row(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Padding(
                                padding: const EdgeInsets.only(left: 5.0),
                                child: CachedNetworkImage(
                                  imageUrl: data[index].image!,
                                  fit: BoxFit.cover,
                                  placeholder: (context, url) => Center(
                                      child:
                                          PlatformCircularProgressIndicator()),
                                  errorWidget: (context, url, error) =>
                                      Icon(Icons.error),
                                  height:
                                      MediaQuery.of(context).size.width * 0.18,
                                  width:
                                      MediaQuery.of(context).size.width * 0.18,
                                ),
                              ),
                              Padding(
                                padding: const EdgeInsets.only(
                                    left: 10.0, right: 35.0),
                                child: Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: [
                                    Text(
                                      data[index].name!,
                                      style: TextStyle(
                                          fontWeight: FontWeight.bold,
                                          fontSize: 20.0),
                                    ),
                                    Row(
                                      children: [
                                        Text(
                                          '4.5',
                                          style: TextStyle(
                                              fontSize: 10.0,
                                              fontWeight: FontWeight.w500),
                                        ),
                                        Text(
                                          '(${data[index].restaurantBranch![index]!.feedbacks!.length.toString()} RATING)', //Here on this line getting null because first element is []
                                          style: TextStyle(
                                              fontSize: 10.0,
                                              fontWeight: FontWeight.w500),
                                        )
                                      ],
                                    ),
                                    Padding(
                                      padding: const EdgeInsets.only(top: 5.0),
                                      child: Row(
                                        children: [
                                          ImageIcon(
                                            AssetImage(
                                                'images/food-serving.png'),
                                            size: 15.0,
                                          ),
                                          Text(
                                            'Italian Food - Steake',
                                            style: TextStyle(fontSize: 12.0),
                                          )
                                        ],
                                      ),
                                    ),
                                    Padding(
                                      padding: const EdgeInsets.only(top: 5.0),
                                      child: Row(
                                        children: [
                                          Icon(
                                            Icons.location_on_outlined,
                                            size: 12.0,
                                            color: TuxedoColor.greyColor,
                                          ),
                                          Text(
                                            'Riyadh',
                                            style: TextStyle(
                                                fontSize: 12.0,
                                                fontWeight: FontWeight.w600),
                                          )
                                        ],
                                      ),
                                    )
                                  ],
                                ),
                              ),
                            ],
                          ),
                        ),
                      ],
                    ),
                  )),
            ),
            onTap: () {
              Navigator.push(
                  context,
                  CupertinoPageRoute(
                      builder: (context) => DetailsPage(
                            id: data[index].id!,
                          )));
            },
          );
        });
  }

您还在为 restaurant_branch 数组使用父 listView 的 index 变量。由于 restaurant_branch 是一个不同的数组,如果您想在布局上有效地显示分支,您应该使用嵌套的 ListView。在你的情况下,如果每个 restaurant 没有多个分支,你可以像这样使用它

                              .......
                              Row(
                                  children: [
                                    Text(
                                      '4.5',
                                      style: TextStyle(
                                          fontSize: 10.0,
                                          fontWeight: FontWeight.w500),
                                    ),
                                    Text(
                                      '(${data[index].restaurantBranch![0]!.feedbacks!.length.toString()} RATING)', //Here on this line getting null because first element is []
                                      style: TextStyle(
                                          fontSize: 10.0,
                                          fontWeight: FontWeight.w500),
                                    )
                                  ],
                                ),
                               ......