【问题标题】:Iterating over an array of objects in JSON with Flutter FutureBuilder使用 Flutter FutureBuilder 迭代 JSON 中的对象数组
【发布时间】: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 对象,但我尝试的任何方法似乎都不起作用。

感谢您的帮助!

【问题讨论】:

    标签: json api flutter flutter-futurebuilder flutter-http


    【解决方案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
    ...
    
    • List 等于 List it self
    Future<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&lt;String, dynamic&gt;' has no instance getter 'title'. Receiver: _LinkedHashMap len:5 Tried calling: title
    • itemCount: snapshot.data.length 似乎确实有效,因为它在 json 中获得了正确数量的项目。所以JSON不回来不是问题,它似乎无法获取属性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-12
    • 1970-01-01
    • 2018-06-30
    • 2019-09-12
    • 1970-01-01
    • 2021-01-18
    相关资源
    最近更新 更多