如何在 flutter 中本地获取 json 文件中的 json 数据
how to get the json data in a json file locally in flutter
我正在尝试从 json 文件中获取数据。但我做对了。我不知道这有什么问题。希望得到指点或教程。
我得到的错误是:Undefined name 'breakfast'.
然后,当我将 breakfast 更改为 Breakfast 时,出现错误:Instance member '...' can't be accessed using static access.
Nothing else。我希望得到一个解释。我只是一个 flutter 的新手。我试图在网上寻找问题和解释,但没有解决问题。
代码如下:
```import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:models/Breakfast.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';
import '../constants (2).dart';
import '../constants.dart';
import '../size_config.dart';
class BreakfastCard extends StatefulWidget {
const BreakfastCard({
Key? key,
this.width = 140,
this.aspectRetio = 1.02,
required this.breakfast,
}) : super(key: key);
final double`enter code here` width, aspectRetio;
final Breakfast breakfast;
@override
_BreakfastCardState createState() => _BreakfastCardState();
}
class _BreakfastCardState extends State<BreakfastCard> {
@override
Widget build(BuildContext context) {
SizeConfig().init(context);
return FutureBuilder(
future: loadBreakfast(),
builder: (BuildContext, AsyncSnapshot<dynamic>snapshot){
return Padding(
padding: EdgeInsets.only(left: getProportionateScreenWidth(20)),
child: SizedBox(
width: getProportionateScreenWidth(140),
child: GestureDetector(
onTap: (){},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AspectRatio(
aspectRatio: 1.02,
child: Container(
padding: EdgeInsets.all(getProportionateScreenWidth(20)),
decoration: BoxDecoration(
color: kSecondaryColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(15),
),
child: Hero(
tag: breakfast.id.toString(),
child: Image.asset(breakfast.images[0]),
),
),
),
const SizedBox(height: 10),
Text(
breakfast.title,
style: const TextStyle(color: Colors.black),
maxLines: 2,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${breakfast.calories} cal |",
style: TextStyle(
fontSize: getProportionateScreenWidth(18),
fontWeight: FontWeight.bold,
color: kPrimaryColor,
),
),
Text(
"${breakfast.time} min",
style: TextStyle(
fontSize: getProportionateScreenWidth(18),
fontWeight: FontWeight.w600,
color: kPrimaryColor,
),
),
InkWell(
borderRadius: BorderRadius.circular(50),
onTap: () { breakfast.isFavorite = !breakfast.isFavorite;},
child: Container(
padding: EdgeInsets.all(getProportionateScreenWidth(8)),
height: getProportionateScreenWidth(28),
width: getProportionateScreenWidth(28),
child: SvgPicture.asset(
"assets/icons/Heart Icon_2.svg",
color: breakfast.isFavorite
? const Color(0xFFFF4848)
: const Color(0xFFDBDEE4),
),
),
),
],
)
],
),
),
),
);
}
);
}
Future<String> _loadloadBreakfastAsset() async {
return await rootBundle.loadString('assets/data.json');
}
Future loadBreakfast() async {
String jsonAddress = await _loadloadBreakfastAsset();
final jsonResponse = json.decode(jsonAddress);
Breakfast breakfast = Breakfast.fromJson(jsonResponse);
}
}```
这是模型
class Breakfast {
final int id, time, serving;
final String title, description, calories;
final List <String> procedure;
final List <String> ingredients;
final List <String> naturalFacts;
final List<String> images;
final double rating;
bool isFavorite, isPopular;
Breakfast({
required this.id,
required this.images,
this.rating = 0.0,
this.isFavorite = false,
this.isPopular = false,
required this.title,
required this.time,
required this.description,
required this.ingredients,
required this.procedure,
required this.naturalFacts,
required this.calories,
required this.serving,
});
factory Breakfast.fromJson(Map<String, dynamic> parsedJson) {
var procedureFromJson = parsedJson['procedure'];
var ingredientsFromJson = parsedJson['ingredients'];
var naturalFactsFromJson = parsedJson['naturalFacts'];
var imagesFromJson = parsedJson['images'];
List<String> ingredientsList = ingredientsFromJson.cast<String>();
List<String> procedureList = procedureFromJson.cast<String>();
List<String> imagesList = imagesFromJson.cast<String>();
return new Breakfast(
calories: parsedJson['calories'],
time: parsedJson['time'],
title: parsedJson['title'],
description: parsedJson['description'],
naturalFacts: parsedJson['naturalFacts'],
serving: parsedJson['serving'],
id: parsedJson['id'],
procedure: procedureList,
ingredients: ingredientsList,
images: imagesList,
);
}
}
json数据
[
{
"id": 1,
"rating": 0.0,
"images": [
"assets/images/cilantro.png"
],
"title": "Cilantro and Kale Pesto Toast with a Fried Egg",
"time": 15,
"description": "Sliced bread is the perfect blank canvas, ready to be loaded up with virtuous ingredients.",
" rating": 4.8,
"isFavorite": false,
"isPopular": true,
"calories": "405",
"serving": 1,
"naturalFacts": [
"405 calories",
"protein 15g",
"fat 31g",
"saturated fat 5.8g",
"carbohydrates 16g",
"fiber 1.9g",
"sodium 331mg",
"cholesterol 189mg"
],
"ingredients": [
"¼ cup packed cilantro",
"1 cup packed kale leaves",
"¼ cup extra-virgin olive oil",
"1 tablespoon white balsamic vinegar",
"2 tablespoons hulled hemp seeds*",
"salt",
"Freshly ground pepper",
"1 large slice of whole-wheat toast",
"2 tablespoons unflavored whole-milk Greek yogurt",
"1 fried egg"
],
"procedure": [
"Whirl the cilantro, kale leaves, extra-virgin olive oil, white balsamic vinegar, and hemp seeds* until fairly smooth, scraping inside of bowl.",
"Season with sea salt and freshly ground pepper. Smear a large slice of whole-wheat toast with the yogurt, then with some pesto.",
"Top with a fried egg and more salt and pepper."
]
}
]
从我对您的代码的目视检查来看,我会说首先修复您的 loadBreakfast() 方法。
您的原始代码...
Future loadBreakfast() async {
String jsonAddress = await _loadloadBreakfastAsset();
final jsonResponse = json.decode(jsonAddress);
Breakfast breakfast = Breakfast.fromJson(jsonResponse);
}
Future 是 Dart 中 Promise() 的名称
如果方法 return 是一种未来类型就更好了。你的方法根本没有 return 任何东西。当您的 FutureBuilder 调用 loadBreakfast 时,它可能收到空响应并且没有完成任何工作。
此更改修复了 Future 的 return 问题:
Future<Breakfast> loadBreakfast() async {
String jsonAddress = await _loadloadBreakfastAsset();
final jsonResponse = json.decode(jsonAddress);
// This line is a problem. See my later comments.
// Breakfast breakfast = Breakfast.fromJson(jsonResponse);
return Future<Breakfast>.value(Breakfast.fromJson(jsonResponse));
}
这条线不是你想的那样。
Breakfast breakfast = Breakfast.fromJson(jsonResponse);
这声明了一个名为 'breakfast' 的新变量,将解析后的 JSON 的值赋给它,然后该方法结束并丢弃该变量。
顺便说一句,这是一个依赖副作用的代码示例,您应该重新考虑如何执行此操作。
您在方法开头声明的值没有任何变化。
下面是如何获得你想要的效果。
我假设您想将已解析的 JSON return 分配给您在小部件顶部定义的 'breakfast' 属性。如果是这样,这就是您应该做的。
首先,将文件底部的两个方法移动到_BreakfastCardState 的范围内class。
}<--- move this brace past the end of loadBreakfast()
Future<String> _loadloadBreakfastAsset() async {
return await rootBundle.loadString('assets/data.json');
}
Future loadBreakfast() async {
String jsonAddress = await _loadloadBreakfastAsset();
final jsonResponse = json.decode(jsonAddress);
Breakfast breakfast = Breakfast.fromJson(jsonResponse);
}
这将允许这些方法访问 StatefulWiget 范围内的 breakfast 变量。
现在您想将 loadBreakfast() 更改为这种形式。
Future<Breakfast> loadBreakfast() async {
String jsonAddress = await _loadloadBreakfastAsset();
final jsonResponse = json.decode(jsonAddress);
// This now updates the breakfast property in the main class.
widget.breakfast = Breakfast.fromJson(jsonResponse);
// This return value is thrown away, but this line is necessary to
// resolve the Future call that FutureBuilder is waiting on.
return Future<Breakfast>.value(null);
}
最终效果应该是 FutureBuilder 会等到您解析 JSON 文件并使用其解析值更新 'breakfast',然后您解析 Future。
FutureBuilder 然后调用您的谓词代码,return 应该具有您期望的所有值。
还有一件事:在您拥有 'breakfast.' 的 Widget 代码中,将其更改为 'widget.breakfast.'
如果这对您有效,请将其标记为已接受的答案。
我正在尝试从 json 文件中获取数据。但我做对了。我不知道这有什么问题。希望得到指点或教程。
我得到的错误是:Undefined name 'breakfast'.
然后,当我将 breakfast 更改为 Breakfast 时,出现错误:Instance member '...' can't be accessed using static access.
Nothing else。我希望得到一个解释。我只是一个 flutter 的新手。我试图在网上寻找问题和解释,但没有解决问题。
代码如下:
```import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:models/Breakfast.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';
import '../constants (2).dart';
import '../constants.dart';
import '../size_config.dart';
class BreakfastCard extends StatefulWidget {
const BreakfastCard({
Key? key,
this.width = 140,
this.aspectRetio = 1.02,
required this.breakfast,
}) : super(key: key);
final double`enter code here` width, aspectRetio;
final Breakfast breakfast;
@override
_BreakfastCardState createState() => _BreakfastCardState();
}
class _BreakfastCardState extends State<BreakfastCard> {
@override
Widget build(BuildContext context) {
SizeConfig().init(context);
return FutureBuilder(
future: loadBreakfast(),
builder: (BuildContext, AsyncSnapshot<dynamic>snapshot){
return Padding(
padding: EdgeInsets.only(left: getProportionateScreenWidth(20)),
child: SizedBox(
width: getProportionateScreenWidth(140),
child: GestureDetector(
onTap: (){},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AspectRatio(
aspectRatio: 1.02,
child: Container(
padding: EdgeInsets.all(getProportionateScreenWidth(20)),
decoration: BoxDecoration(
color: kSecondaryColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(15),
),
child: Hero(
tag: breakfast.id.toString(),
child: Image.asset(breakfast.images[0]),
),
),
),
const SizedBox(height: 10),
Text(
breakfast.title,
style: const TextStyle(color: Colors.black),
maxLines: 2,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${breakfast.calories} cal |",
style: TextStyle(
fontSize: getProportionateScreenWidth(18),
fontWeight: FontWeight.bold,
color: kPrimaryColor,
),
),
Text(
"${breakfast.time} min",
style: TextStyle(
fontSize: getProportionateScreenWidth(18),
fontWeight: FontWeight.w600,
color: kPrimaryColor,
),
),
InkWell(
borderRadius: BorderRadius.circular(50),
onTap: () { breakfast.isFavorite = !breakfast.isFavorite;},
child: Container(
padding: EdgeInsets.all(getProportionateScreenWidth(8)),
height: getProportionateScreenWidth(28),
width: getProportionateScreenWidth(28),
child: SvgPicture.asset(
"assets/icons/Heart Icon_2.svg",
color: breakfast.isFavorite
? const Color(0xFFFF4848)
: const Color(0xFFDBDEE4),
),
),
),
],
)
],
),
),
),
);
}
);
}
Future<String> _loadloadBreakfastAsset() async {
return await rootBundle.loadString('assets/data.json');
}
Future loadBreakfast() async {
String jsonAddress = await _loadloadBreakfastAsset();
final jsonResponse = json.decode(jsonAddress);
Breakfast breakfast = Breakfast.fromJson(jsonResponse);
}
}```
这是模型
class Breakfast {
final int id, time, serving;
final String title, description, calories;
final List <String> procedure;
final List <String> ingredients;
final List <String> naturalFacts;
final List<String> images;
final double rating;
bool isFavorite, isPopular;
Breakfast({
required this.id,
required this.images,
this.rating = 0.0,
this.isFavorite = false,
this.isPopular = false,
required this.title,
required this.time,
required this.description,
required this.ingredients,
required this.procedure,
required this.naturalFacts,
required this.calories,
required this.serving,
});
factory Breakfast.fromJson(Map<String, dynamic> parsedJson) {
var procedureFromJson = parsedJson['procedure'];
var ingredientsFromJson = parsedJson['ingredients'];
var naturalFactsFromJson = parsedJson['naturalFacts'];
var imagesFromJson = parsedJson['images'];
List<String> ingredientsList = ingredientsFromJson.cast<String>();
List<String> procedureList = procedureFromJson.cast<String>();
List<String> imagesList = imagesFromJson.cast<String>();
return new Breakfast(
calories: parsedJson['calories'],
time: parsedJson['time'],
title: parsedJson['title'],
description: parsedJson['description'],
naturalFacts: parsedJson['naturalFacts'],
serving: parsedJson['serving'],
id: parsedJson['id'],
procedure: procedureList,
ingredients: ingredientsList,
images: imagesList,
);
}
}
json数据
[
{
"id": 1,
"rating": 0.0,
"images": [
"assets/images/cilantro.png"
],
"title": "Cilantro and Kale Pesto Toast with a Fried Egg",
"time": 15,
"description": "Sliced bread is the perfect blank canvas, ready to be loaded up with virtuous ingredients.",
" rating": 4.8,
"isFavorite": false,
"isPopular": true,
"calories": "405",
"serving": 1,
"naturalFacts": [
"405 calories",
"protein 15g",
"fat 31g",
"saturated fat 5.8g",
"carbohydrates 16g",
"fiber 1.9g",
"sodium 331mg",
"cholesterol 189mg"
],
"ingredients": [
"¼ cup packed cilantro",
"1 cup packed kale leaves",
"¼ cup extra-virgin olive oil",
"1 tablespoon white balsamic vinegar",
"2 tablespoons hulled hemp seeds*",
"salt",
"Freshly ground pepper",
"1 large slice of whole-wheat toast",
"2 tablespoons unflavored whole-milk Greek yogurt",
"1 fried egg"
],
"procedure": [
"Whirl the cilantro, kale leaves, extra-virgin olive oil, white balsamic vinegar, and hemp seeds* until fairly smooth, scraping inside of bowl.",
"Season with sea salt and freshly ground pepper. Smear a large slice of whole-wheat toast with the yogurt, then with some pesto.",
"Top with a fried egg and more salt and pepper."
]
}
]
从我对您的代码的目视检查来看,我会说首先修复您的 loadBreakfast() 方法。
您的原始代码...
Future loadBreakfast() async {
String jsonAddress = await _loadloadBreakfastAsset();
final jsonResponse = json.decode(jsonAddress);
Breakfast breakfast = Breakfast.fromJson(jsonResponse);
}
Future 是 Dart 中 Promise() 的名称
如果方法 return 是一种未来类型就更好了。你的方法根本没有 return 任何东西。当您的 FutureBuilder 调用 loadBreakfast 时,它可能收到空响应并且没有完成任何工作。
此更改修复了 Future 的 return 问题:
Future<Breakfast> loadBreakfast() async {
String jsonAddress = await _loadloadBreakfastAsset();
final jsonResponse = json.decode(jsonAddress);
// This line is a problem. See my later comments.
// Breakfast breakfast = Breakfast.fromJson(jsonResponse);
return Future<Breakfast>.value(Breakfast.fromJson(jsonResponse));
}
这条线不是你想的那样。
Breakfast breakfast = Breakfast.fromJson(jsonResponse);
这声明了一个名为 'breakfast' 的新变量,将解析后的 JSON 的值赋给它,然后该方法结束并丢弃该变量。
顺便说一句,这是一个依赖副作用的代码示例,您应该重新考虑如何执行此操作。
您在方法开头声明的值没有任何变化。 下面是如何获得你想要的效果。
我假设您想将已解析的 JSON return 分配给您在小部件顶部定义的 'breakfast' 属性。如果是这样,这就是您应该做的。
首先,将文件底部的两个方法移动到_BreakfastCardState 的范围内class。
}<--- move this brace past the end of loadBreakfast()
Future<String> _loadloadBreakfastAsset() async {
return await rootBundle.loadString('assets/data.json');
}
Future loadBreakfast() async {
String jsonAddress = await _loadloadBreakfastAsset();
final jsonResponse = json.decode(jsonAddress);
Breakfast breakfast = Breakfast.fromJson(jsonResponse);
}
这将允许这些方法访问 StatefulWiget 范围内的 breakfast 变量。
现在您想将 loadBreakfast() 更改为这种形式。
Future<Breakfast> loadBreakfast() async {
String jsonAddress = await _loadloadBreakfastAsset();
final jsonResponse = json.decode(jsonAddress);
// This now updates the breakfast property in the main class.
widget.breakfast = Breakfast.fromJson(jsonResponse);
// This return value is thrown away, but this line is necessary to
// resolve the Future call that FutureBuilder is waiting on.
return Future<Breakfast>.value(null);
}
最终效果应该是 FutureBuilder 会等到您解析 JSON 文件并使用其解析值更新 'breakfast',然后您解析 Future。
FutureBuilder 然后调用您的谓词代码,return 应该具有您期望的所有值。
还有一件事:在您拥有 'breakfast.' 的 Widget 代码中,将其更改为 'widget.breakfast.'
如果这对您有效,请将其标记为已接受的答案。