使用 Flutter FutureBuilder 迭代 JSON 中的对象数组
Posted
技术标签:
【中文标题】使用 Flutter FutureBuilder 迭代 JSON 中的对象数组【英文标题】:Iterating over an array of objects in JSON with Flutter FutureBuilder 【发布时间】:2021-08-30 18:02:47 【问题描述】:我在尝试使用 Flutter 的 FutureBuilder 从远程 URL 迭代 JSON 对象数组时遇到问题。
我的目标是:
从 API 获取 JSON 数据 将数据输出到 2 列 gridview 布局中JSON 数据是一个对象数组(或 dart 中的 Maps 列表),对象具有简单的字符串数据。
我知道我需要构建一个 future 来从 API 获取数据并解码 JSON,然后我需要创建一个 FutureBuilder 来将 List 数据输出到我的 Gridview Builder 中。这就是我在下面的代码中尝试做的事情。
import 'dart:convert';
import 'dart:async';
import 'dart:core';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class HomeSection extends StatefulWidget
@override
_HomeSectionState createState() => _HomeSectionState();
class _HomeSectionState extends State<HomeSection>
@override
void initState()
super.initState();
Future<List<dynamic>> fetchSectionData() async
String dataUrl =
'https://www.thisisthejsonapilink.co.uk/fetch-data';
var response = await http.get(Uri.parse(dataUrl));
if (response.statusCode == 200)
return jsonDecode(response.body);
else
throw Exception('Failed to get the data');
@override
Widget build(BuildContext context)
return FutureBuilder(
future: fetchSectionData,
builder: (context, snapshot)
if (snapshot.connectionState == ConnectionState.done)
return GridView.builder(
itemCount: 12,
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 300,
crossAxisSpacing: 16.0,
mainAxisSpacing: 18.0,
childAspectRatio: MediaQuery.of(context).size.height / 930,
),
itemBuilder: (BuildContext context, int index) => GestureDetector(
onTap: ()
Navigator.push(
context,
MaterialPageRoute(builder: (context) => OtherScreen()),
);
,
child: Column(
children: [
Container(
margin: const EdgeInsets.only(bottom: 12.0),
height: 144,
),
Text(
snapshot.data[index].title,
),
Text(
snapshot.data[index].duration + ' - ' + snapshot.data[index].type,
),
],
),
),
);
else
return Center(
child: CircularProgressIndicator(
color: Colors.black,
),
);
,
);
我从 API 链接返回的 JSON 结构如下:
[
"Title": "Audio 1",
"Duration": "5 min",
"type": "audio",
"bodyText": "lorem ipsum blah blah audio",
"url": "https://www.silvermansound.com/music/dirty-gertie.mp3"
,
"Title": "Video 1",
"Duration": "5 min",
"type": "video",
"bodyText": "lorem ipsum blah blah video",
"url": "https://assets.mixkit.co/videos/preview/mixkit-woman-wearing-a-mask-while-running-40158-large.mp4"
,
"Title": "Audio 2",
"Duration": "5 min",
"type": "audio",
"bodyText": "lorem ipsum blah blah audio",
"url": "https://www.silvermansound.com/music/dirty-gertie.mp3"
,
"Title": "Video 2",
"Duration": "5 min",
"type": "video",
"bodyText": "lorem ipsum blah blah video",
"url": "https://assets.mixkit.co/videos/preview/mixkit-woman-wearing-a-mask-while-running-40158-large.mp4"
,
"Title": "Audio 3",
"Duration": "5 min",
"type": "audio",
"bodyText": "lorem ipsum blah blah audio",
"url": "https://www.silvermansound.com/music/dirty-gertie.mp3"
,
"Title": "Video 3",
"Duration": "5 min",
"type": "video",
"bodyText": "lorem ipsum blah blah video",
"url": "https://assets.mixkit.co/videos/preview/mixkit-woman-wearing-a-mask-while-running-40158-large.mp4"
,
]
这是我在 VS 代码调试控制台中遇到的错误:
The argument type 'Future<List<dynamic>> Function()' can't be assigned to the parameter type 'Future<Object?>?'.
红线出现在我试图在 FutureBuilder 中定义我的未来的地方fetchSectionData
:
return FutureBuilder(
future: fetchSectionData,
builder: (context, snapshot)
我不确定这个错误是什么意思。有人可以解释一下吗? Future 肯定会返回一个 ,但是如何将此列表放入 futurebuilder 中,以便我可以对其进行迭代并将数据输出到 gridview 中?
我是 Flutter 的新手,来自 javascript 网络背景,通常在 javascript 中,您可以循环遍历数组并以这种方式输出。我很想在这里这样做,但我知道那是不对的。
当我查看有关如何从互联网获取数据的 Flutter 文档时,它提到我必须将响应转换为自定义 dart 对象,但我尝试的任何方法似乎都不起作用。
感谢您的帮助!
【问题讨论】:
【参考方案1】:试试这个!
return FutureBuilder<List<dynamic>>(
future: fetchSectionData,
builder: (context, snapshot)
if (snapshot.connectionState == ConnectionState.done)
return GridView.builder(
itemCount: 12,
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 300,
crossAxisSpacing: 16.0,
mainAxisSpacing: 18.0,
childAspectRatio: MediaQuery.of(context).size.height / 930,
),
itemBuilder: (BuildContext context, int index) => GestureDetector(
onTap: ()
Navigator.push(
context,
MaterialPageRoute(builder: (context) => OtherScreen()),
);
,
child: Column(
children: [
Container(
margin: const EdgeInsets.only(bottom: 12.0),
height: 144,
),
Text(
'$snapshot.data[index]['Title']',
),
Text(
'$snapshot.data[index]['Duration'] + ' - ' + snapshot.data[index]['type']',
),
],
),
),
);
else
return Center(
child: CircularProgressIndicator(
color: Colors.black,
),
);
,
);
【讨论】:
我必须对其添加空检查并将底部更改为:$snapshot.data[index]['Duration'] + ' - ' + snapshot.data[index]['type']
但它有效。我还必须记住属性名称区分大小写。谢谢!【参考方案2】:
你必须像这样传递函数
future: fetchSectionData(),
最好在您的 GridView 中使用
...
itemCount: snapshot.data.length
...
ListFuture<List> fetchSectionData() async
...
最好确定 FutureBuilder 的类型
FutureBuilder<List>(
...
【讨论】:
itemCount: snapshot.data.length
我已经添加了这个,我在调试控制台中收到了这个错误:The property 'length' can't be unconditionally accessed because the receiver can be 'null'. Try making the access conditional (using '?.') or adding a null check to the target ('!').
在snapshot.data[index].title,
行下我也收到错误The method '[]' can't be unconditionally invoked because the receiver can be 'null'. Try making the call conditional (using '?.') or adding a null check to the target ('!').
我认为这是一个空安全的事情
@danny471 这是 dart null 安全功能的 bc,添加!给他们,例如。 snapshot.data![index] 快照.data!.length
我试过了,但我现在在调试控制台中收到此错误:════════ Exception caught by widgets library ═══════════════════════════════════ Class '_InternalLinkedHashMap<String, dynamic>' has no instance getter 'title'. Receiver: _LinkedHashMap len:5 Tried calling: title
itemCount: snapshot.data.length
似乎确实有效,因为它在 json 中获得了正确数量的项目。所以JSON不回来不是问题,它似乎无法获取属性。以上是关于使用 Flutter FutureBuilder 迭代 JSON 中的对象数组的主要内容,如果未能解决你的问题,请参考以下文章
Flutter StreamBuilder 与 FutureBuilder
使用 Mockito 的 FutureBuilder 快照数据为空 - Flutter
Flutter 使用 FutureBuilder 检索列表中的数据
FutureBuilder 能够获取数据,但使用 Flutter 多次获取数据