我正在尝试从与文本字段匹配的 Nutritionx API 中获取所有数据并将其显示为列表 目标是让用户搜索食物名称并将它们列在列表中。
这是营养的文档x- https://docs.google.com/document/d/1_q-K-ObMTZvO0qUEAxROrN3bwMujwAN25sLHwJzliK0/edit#
这是一个示例响应-
{
"branded": [
{
"food_name": "Grilled Cheese",
"image": null,
"serving_unit": "serving",
"nix_brand_id": "513fbc1283aa2dc80c000358",
"brand_name_item_name": "Claim Jumper Grilled Cheese",
"serving_qty": 1,
"nf_calories": 560,
"brand_name": "Claim Jumper",
"brand_type": 1,
"nix_item_id": "529e800af9655f6d3500c710"
},
{
"food_name": "Grilled Cheesewich",
"image": null,
"serving_unit": "serving",
"nix_brand_id": "521b95434a56d006cae29678",
"brand_name_item_name": "Red Robin Grilled Cheesewich",
"serving_qty": 1,
"nf_calories": 550,
"brand_name": "Red Robin",
"brand_type": 1,
"nix_item_id": "52cdccf0051cb9eb320054c6"
},
{
"food_name": "Grilled Cheese Melts",
"image": "https://d1r9wva3zcpswd.cloudfront.net/54ca49ac6f1a024b0f919764.jpeg",
"serving_unit": "slice",
"nix_brand_id": "51db37b5176fe9790a8988dd",
"brand_name_item_name": "Borden Grilled Cheese Melts",
"serving_qty": 1,
"nf_calories": 50,
"brand_name": "Borden",
"brand_type": 2,
"nix_item_id": "54ca48fc064e3a791d6737b0"
},
{
"food_name": "Kid's Grilled Cheese",
"image": null,
"serving_unit": "serving",
"nix_brand_id": "521b95494a56d006cae2a612",
"brand_name_item_name": "Larkburger Kid's Grilled Cheese",
"serving_qty": 1,
"nf_calories": 500,
"brand_name": "Larkburger",
"brand_type": 1,
"nix_item_id": "529e80ceea63d4933500fc87"
}
],
"self": [
{
"food_name": "grilled cheese",
"serving_unit": "sandwich",
"nix_brand_id": null,
"serving_qty": 1,
"nf_calories": 348.4,
"brand_name": null,
"uuid": "7e79cdfa-bb3f-4f3b-a292-3357aa35d31f",
"nix_item_id": null
},
{
"food_name": "cheeseburgers",
"serving_unit": "item",
"nix_brand_id": null,
"serving_qty": 1.5,
"nf_calories": 802.97,
"brand_name": null,
"uuid": "5a63f2af-34b2-4137-bf14-5d95eabcf12d",
"nix_item_id": null
}
],
"common": [
{
"food_name": "grilled cheese",
"image": "https://d2xdmhkmkbyw75.cloudfront.net/1763_thumb.jpg",
"tag_id": "1763",
"tag_name": "grilled cheese"
},
{
"food_name": "grilled cheeses",
"image": "https://d2xdmhkmkbyw75.cloudfront.net/1763_thumb.jpg",
"tag_id": "1763",
"tag_name": "grilled cheese"
},
{
"food_name": "grilled cheese cheeseburger melt",
"image": null,
"tag_id": "5901",
"tag_name": "grilled cheese burger"
},
{
"food_name": "grilled cheese cheeseburger",
"image": null,
"tag_id": "5901",
"tag_name": "grilled cheese burger"
},
{
"food_name": "grilled cheese burger",
"image": null,
"tag_id": "5901",
"tag_name": "grilled cheese burger"
}
]
}
这是我的代码-
import 'dart:async';
import 'dart:convert';
import 'foodModel.dart';
import 'package:fit_app/fitness_app_theme.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
Future<List<Autogenerated>> fetchDishes(http.Client client, String query) async {
final response = await client.get(
'https://trackapi.nutritionix.com/v2/search/instant?query=$query',
headers: {
"x-app-id": "26706c4b",
"x-app-key": "496693e69b3996ce96fec5eeb79a3c26",
},
);
return compute(parseDishes, response.body);
}
List<Autogenerated> parseDishes(String responseBody) {
final parsed = jsonDecode(responseBody);
print(parsed);
if(parsed is List)
{
return parsed.map<Autogenerated>((json) => Autogenerated.fromJson(json)).toList();
}
else
{
return [parsed];
}
}
class FoodPage extends StatefulWidget {
FoodPage({Key key}) : super(key: key);
@override
_FoodPageState createState() => _FoodPageState();
}
class _FoodPageState extends State<FoodPage> {
TextEditingController editingController = TextEditingController();
List<Autogenerated> dishes;
List<Autogenerated> tempDishes = List<Autogenerated>();
List<Autogenerated> dummySearchList = List<Autogenerated>();
Widget _widget = Container();
var energy;
@override
void initState() {
super.initState();
}
Future<List<Autogenerated>> filterSearchResults (String query) async{
_widget = FutureBuilder<List<Autogenerated>>(
future: fetchDishes(http.Client(), editingController.text),
builder: (context, snapshot) {
if (snapshot.hasData) {
dishes = snapshot.data;
tempDishes.clear();
tempDishes.addAll(dishes);
return ListView.builder(
itemCount: tempDishes.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text(tempDishes[index].common[index].foodName, style: TextStyle(color: Colors.white),),
subtitle: Text('Energy - $energy', style: TextStyle(color: Colors.white))
),
color: FitnessAppTheme.nearlyDark,);
},
);
} else
{
return Center(child: CircularProgressIndicator());
}
}
);
}
@override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: FitnessAppTheme.darkBackground,
body: SafeArea(
top: true,
child: Container(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
style: TextStyle(color: Colors.white),
onChanged: (value) async {
await filterSearchResults(value);
},
controller: editingController,
decoration: InputDecoration(
hintStyle: TextStyle(color: FitnessAppTheme.white),
labelStyle: TextStyle(color: FitnessAppTheme.white),
labelText: "Search",
hintText: "Search",
prefixIcon: Icon(Icons.search, color: Colors.white,),
enabledBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(25.0)),
borderSide: const BorderSide(color: Colors.white, width: 1.0)
),
border: const OutlineInputBorder()
),
),
),
Expanded(
child: _widget,
),
],
),
),
),
);
}
}
这是模型-
class Autogenerated {
List<Branded> branded;
List<Self> self;
List<Common> common;
Autogenerated({this.branded, this.self, this.common});
Autogenerated.fromJson(Map<String, dynamic> json) {
if (json['branded'] != null) {
branded = new List<Branded>();
json['branded'].forEach((v) {
branded.add(new Branded.fromJson(v));
});
}
if (json['self'] != null) {
self = new List<Self>();
json['self'].forEach((v) {
self.add(new Self.fromJson(v));
});
}
if (json['common'] != null) {
common = new List<Common>();
json['common'].forEach((v) {
common.add(new Common.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.branded != null) {
data['branded'] = this.branded.map((v) => v.toJson()).toList();
}
if (this.self != null) {
data['self'] = this.self.map((v) => v.toJson()).toList();
}
if (this.common != null) {
data['common'] = this.common.map((v) => v.toJson()).toList();
}
return data;
}
}
class Branded {
String foodName;
String image;
String servingUnit;
String nixBrandId;
String brandNameItemName;
int servingQty;
int nfCalories;
String brandName;
int brandType;
String nixItemId;
Branded(
{this.foodName,
this.image,
this.servingUnit,
this.nixBrandId,
this.brandNameItemName,
this.servingQty,
this.nfCalories,
this.brandName,
this.brandType,
this.nixItemId});
Branded.fromJson(Map<String, dynamic> json) {
foodName = json['food_name'];
image = json['image'];
servingUnit = json['serving_unit'];
nixBrandId = json['nix_brand_id'];
brandNameItemName = json['brand_name_item_name'];
servingQty = json['serving_qty'];
nfCalories = json['nf_calories'];
brandName = json['brand_name'];
brandType = json['brand_type'];
nixItemId = json['nix_item_id'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['food_name'] = this.foodName;
data['image'] = this.image;
data['serving_unit'] = this.servingUnit;
data['nix_brand_id'] = this.nixBrandId;
data['brand_name_item_name'] = this.brandNameItemName;
data['serving_qty'] = this.servingQty;
data['nf_calories'] = this.nfCalories;
data['brand_name'] = this.brandName;
data['brand_type'] = this.brandType;
data['nix_item_id'] = this.nixItemId;
return data;
}
}
class Self {
String foodName;
String servingUnit;
Null nixBrandId;
double servingQty;
double nfCalories;
Null brandName;
String uuid;
Null nixItemId;
Self(
{this.foodName,
this.servingUnit,
this.nixBrandId,
this.servingQty,
this.nfCalories,
this.brandName,
this.uuid,
this.nixItemId});
Self.fromJson(Map<String, dynamic> json) {
foodName = json['food_name'];
servingUnit = json['serving_unit'];
nixBrandId = json['nix_brand_id'];
servingQty = json['serving_qty'];
nfCalories = json['nf_calories'];
brandName = json['brand_name'];
uuid = json['uuid'];
nixItemId = json['nix_item_id'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['food_name'] = this.foodName;
data['serving_unit'] = this.servingUnit;
data['nix_brand_id'] = this.nixBrandId;
data['serving_qty'] = this.servingQty;
data['nf_calories'] = this.nfCalories;
data['brand_name'] = this.brandName;
data['uuid'] = this.uuid;
data['nix_item_id'] = this.nixItemId;
return data;
}
}
class Common {
String foodName;
String image;
String tagId;
String tagName;
Common({this.foodName, this.image, this.tagId, this.tagName});
Common.fromJson(Map<String, dynamic> json) {
foodName = json['food_name'];
image = json['image'];
tagId = json['tag_id'];
tagName = json['tag_name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['food_name'] = this.foodName;
data['image'] = this.image;
data['tag_id'] = this.tagId;
data['tag_name'] = this.tagName;
return data;
}
}
错误-
Unhandled Exception: Exception: NoSuchMethodError: Class '_InternalLinkedHashMap<String, dynamic>' has no instance method 'map' with matching arguments.
E/flutter ( 8271): Receiver: _LinkedHashMap len:2
E/flutter ( 8271): Tried calling: map<Autogenerated>(Closure: (dynamic) => Autogenerated)
E/flutter ( 8271): Found: map<K2, V2>((K, V) => MapEntry<K2, V2>) => Map<K2, V2>
E/flutter ( 8271): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:54:5)
E/flutter ( 8271): #1 parseDishes (package:fit_app/ui_view/add_food.dart:21:17)
E/flutter ( 8271): #2 _IsolateConfiguration.apply (package:flutter/src/foundation/_isolates_io.dart:81:34)
E/flutter ( 8271): #3 _spawn.<anonymous closure> (package:flutter/src/foundation/_isolates_io.dart:88:65)
E/flutter ( 8271): #4 _spawn.<anonymous closure> (package:flutter/src/foundation/_isolates_io.dart:87:5)
E/flutter ( 8271): #5 Timeline.timeSync (dart:developer/timeline.dart:163:22)
E/flutter ( 8271): #6 _spawn (package:flutter/src/foundation/_isolates_io.dart:85:35)
E/flutter ( 8271): #7 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:286:17)
E/flutter ( 8271): #8 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
E/flutter ( 8271):
我做错了什么?
编辑-
错误-
Unhandled Exception: Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Autogenerated'
E/flutter ( 8671): #0 parseDishes (package:fit_app/ui_view/add_food.dart:30:13)
E/flutter ( 8671): #1 _IsolateConfiguration.apply (package:flutter/src/foundation/_isolates_io.dart:81:34)
E/flutter ( 8671): #2 _spawn.<anonymous closure> (package:flutter/src/foundation/_isolates_io.dart:88:65)
E/flutter ( 8671): #3 _spawn.<anonymous closure> (package:flutter/src/foundation/_isolates_io.dart:87:5)
E/flutter ( 8671): #4 Timeline.timeSync (dart:developer/timeline.dart:163:22)
E/flutter ( 8671): #5 _spawn (package:flutter/src/foundation/_isolates_io.dart:85:35)
E/flutter ( 8671): #6 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:286:17)
E/flutter ( 8671): #7 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
E/flutter ( 8671):
编辑- 我每次都设置一个小部件并在构建中使用它-
_widget = FutureBuilder<List<Autogenerated>>(
future: fetchDishes(http.Client(), editingController.text),
builder: (context, snapshot) {
if (snapshot.hasData) {
dishes = snapshot.data;
tempDishes.clear();
tempDishes.addAll(dishes);
return ListView.builder(
itemCount: tempDishes[0].common.length,
itemBuilder: (context, index) {
print(tempDishes[0].common.length);
return Card(
child: ListTile(
title: Text(tempDishes[0].common[index].foodName),
subtitle: Text('Energy - $energy', style: TextStyle(color: Colors.white))
),
color: FitnessAppTheme.nearlyDark,);
},
);
} else
{
return Center(child: CircularProgressIndicator());
}
}
);