#json #flutter #dart #flutter-bloc
Вопрос:
Я пытаюсь получить API с помощью flutter_bloc
библиотеки узор и я успешно в состоянии получить данные, но проблема заключается в Ниже я упомянул json
данные первых двух элементов имеет пустой []
массив restaurant_branch
и последний (третий) элемент данных, в restaurant_branch
которой результат нулевой точки исключением («RangeError (индекс): недопустимое значение: допустимый диапазон значений пуст: 0») в HomePage.dart
( в текст виджета) коду. Итак, как предотвратить эту проблему.
данные json
{
"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
}
]
},
]
}
Рекомендуется для вашей модели
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;
}
}
Домашняя страница.дарт
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!,
)));
},
);
});
}
Ответ №1:
Вы index
также используете переменную родительского представления списка для restaurant_branch
массива. Поскольку restaurant_branch
это другой массив, вам следует использовать вложенный список, если вы хотите эффективно отображать ветви на макете. В вашем случае, если у 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),
)
],
),
......
Комментарии:
1. Как можно иметь вложенное представление списка внутри этого виджета
Widget buildRecommendationRestaurant(List<RecommendedForYouData> data)
. Выше я обновилHomePage.dart
код, чтобы вы могли более четко понимать2. Я просто говорю, что вам следует подумать о создании вложенных списков. В настоящее время в вашем коде, если у ресторана несколько филиалов, он не будет показывать общую обратную связь каждого филиала (вместо этого он показывает общую обратную связь первого филиала — или какой-либо другой ветви).
3. Поэтому я должен создать пользовательский виджет
List< RecommendedForYouDataRestaurantBranch >
, правильно ли это ?4. Да, все зависит от того, как вы разрабатываете свое приложение
5. Я также попробовал использовать тернарный оператор, изначально он работал, но когда я достигаю этого элемента, содержащего данные, он показывает ошибку
data[index].restaurantBranch!.length != 0 ? Text( '(${data[index].restaurantBranch![index]!.feedbacks!.length.toString()} RATING)',style: TextStyle(fontSize: 10.0,fontWeight:FontWeight.w500),): Text(''),