flutter 如何显示从API获取的数据?

baubqpgj  于 2023-02-05  发布在  Flutter
关注(0)|答案(2)|浏览(167)

我已经从API中获取了行星的详细信息,即(NOM)卫星数量、重力和密度。我已经将这些详细信息存储在PlanetInfo数组中。我希望使用文本小部件(如Text("${PlanetInfo [1 ]}",样式:文本样式(颜色:颜色。白色))。但它给了我一个错误:范围错误(索引):无效值:有效值范围为空:1

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:xperience/Models/planets.dart';

class PlanetDescNoMGD extends StatelessWidget {
  final Planet planeteee;
  List PlanetInfo = [];
  getPlanetData() async {
    var url =
        "https://api.le-systeme-solaire.net/rest/bodies/${planeteee.planetApi}";
    final uri = Uri.parse(url);
    final response = await http.get(uri);
    final body = response.body;
    final jsondata = jsonDecode(body);

    PlanetInfo.add(jsondata["moons"].length);
    PlanetInfo.add(jsondata["gravity"]);
    PlanetInfo.add(jsondata["density"]);
  }

  PlanetDescNoMGD({Key? key, required this.planeteee}) : super(key: key);
  @override
  void initState() {
    this.getPlanetData();
  }

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      children: <Widget>[
        Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            const Text(
              "No. of moons",
              style:
                  TextStyle(color: Colors.white, fontWeight: FontWeight.w700),
            ),
            const SizedBox(
              height: 12,
            ),
            Text("${PlanetInfo[1]}", style: TextStyle(color: Colors.white))
          ],
        ),
        Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            const Text(
              "Gravity",
              style:
                  TextStyle(color: Colors.white, fontWeight: FontWeight.w600),
            ),
            const SizedBox(
              height: 12,
            ),
            Text("${PlanetInfo[1]}" + " m/s²",
                style: TextStyle(color: Colors.white))
            //Text(${num} + " m/s²", style: TextStyle(color: Colors.white))
          ],
        ),
        Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            const Text(
              "Density",
              style:
                  TextStyle(color: Colors.white, fontWeight: FontWeight.w600),
            ),
            const SizedBox(
              height: 12,
            ),
            Text("${PlanetInfo[2]}" + " g/cm3",
                style: TextStyle(color: Colors.white))
          ],
        ),
      ],
    );
  }
}

我需要一个解决办法。

v8wbuo2f

v8wbuo2f1#

1.您不知道如何使用异步函数。请学习它。您正在向API发出异步请求,并直接尝试使用来自API的响应。这是不可能的。发生的情况是,当调用构建时,您的列表PlanetInfo为空。因此,您将收到错误。
1.无状态小部件没有initState!我发现您试图覆盖不存在的initState。
1.您需要有状态的小部件来使用setState。
1.下面是代码的最小修改工作版本。加载数据后需要使用setState,并更改isLoaded = true。
解决方案如下:

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:xperience/Models/planets.dart';

class PlanetDescNoMGD extends StatefulWidget {
  PlanetDescNoMGD({Key? key, required this.planeteee}) : super(key: key);

  final Planet planeteee;

  @override
  State<PlanetDescNoMGD> createState() => _PlanetDescNoMGDState();
}

class _PlanetDescNoMGDState extends State<PlanetDescNoMGD> {
  List PlanetInfo = [];

  bool isLoaded = false;

  getPlanetData() async {
    var url =
        "https://api.le-systeme-solaire.net/rest/bodies/${widget.planeteee.planetApi}";
    final uri = Uri.parse(url);
    final response = await http.get(uri);
    final body = response.body;
    final jsondata = jsonDecode(body);

    PlanetInfo.add(jsondata["moons"].length);
    PlanetInfo.add(jsondata["gravity"]);
    PlanetInfo.add(jsondata["density"]);
    setState(() {
      isLoaded = true;
    });
  }

  @override
  void initState() {
    super.initState();
    getPlanetData();
  }

  @override
  Widget build(BuildContext context) {
    return !isLoaded
        ? const Center(child: CircularProgressIndicator())
        : Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: <Widget>[
              Column(
                crossAxisAlignment: CrossAxisAlignment.center,
                children: <Widget>[
                  const Text(
                    "No. of moons",
                    style: TextStyle(
                        color: Colors.white, fontWeight: FontWeight.w700),
                  ),
                  const SizedBox(
                    height: 12,
                  ),
                  Text("${PlanetInfo[1]}",
                      style: TextStyle(color: Colors.white))
                ],
              ),
              Column(
                crossAxisAlignment: CrossAxisAlignment.center,
                children: <Widget>[
                  const Text(
                    "Gravity",
                    style: TextStyle(
                        color: Colors.white, fontWeight: FontWeight.w600),
                  ),
                  const SizedBox(
                    height: 12,
                  ),
                  Text("${PlanetInfo[1]}" + " m/s²",
                      style: TextStyle(color: Colors.white))
                  //Text(${num} + " m/s²", style: TextStyle(color: Colors.white))
                ],
              ),
              Column(
                crossAxisAlignment: CrossAxisAlignment.center,
                children: <Widget>[
                  const Text(
                    "Density",
                    style: TextStyle(
                        color: Colors.white, fontWeight: FontWeight.w600),
                  ),
                  const SizedBox(
                    height: 12,
                  ),
                  Text("${PlanetInfo[2]}" + " g/cm3",
                      style: TextStyle(color: Colors.white))
                ],
              ),
            ],
          );
  }
}
suzh9iv8

suzh9iv82#

你有两件事要解决。
1.上课。
不要将PlanetInfo用作int列表,充分利用定义类的功能:封装数据并提高可读性。
按如下所示定义类

PlanetInfo{
int noOfMoons;
double gravity;
double density;
PlanetInfo({
 required this.noOfMoons,
 required this.gravity,
 required this.density,
 });
}

在州里宣布一个成员。

List PlanetInfo = [];//remove this
late final PlanetInfo myPlanet;// use this

现在,在fetch调用中创建一个对象,并将其分配给状态成员。

final jsondata = jsonDecode(body);

    PlanetInfo tempPlanet=PlanetInfo(
               noOfMoons: jsondata["moons"].length,
               gravity: jsondata["gravity"],
               density: jsondata["density"],
);
myPlanet=x; // use setState() if required

并使用属性显示在窗口小部件中。

//rest of code

    Text("${planetInfo.noOfMoons}",

 //rest of code

     Text("${planetInfo.gravity}}" + " m/s²",'

 //rest of code  
            
     Text("${planetInfo.density}" + " g/cm3",

 //rest of code

1.显示API数据。
您可以使用FutureBuilder等待构建UI,直到API调用完成,或者按照@hiloliddin建议的操作(使用isLoaded成员并基于其值构建UI)。
在您当前的实现中,由于UI是在API调用完成之前构建的,并且列表PlanetInfo为空,因此您会收到该错误。

相关问题