首页 > 解决方案 > Flutter RangeError(索引):无效值:有效值范围为空:0

问题描述

我从我的 api 获取数据之前我正在起诉硬编码的 json 数据,因此它在应用程序中完美运行,但现在当我使用 API 数据时,它显示此错误

RangeError(索引):无效值:有效值范围为空:0

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool showApp = false;
   var _questions = new List<Questions>();
  _getQuestions() {
    API.getUsers().then((response) {
      setState(() {

        Iterable list = json.decode(response.body);
        print(list);
        print(list);
        _questions = list.map((model) => Questions.fromJson(model)).toList();
        print(_questions);
        showApp = true;
      });
    });
  }
  initState() {
    super.initState();
    _getQuestions();
  }

  int index = 0;
  bool shouldShow = false;

  @override
  Widget build(BuildContext context) {

    int size = _questions.length;

    void nextQuestion() {
      if (index < size - 1)
        setState(() {
          index++;
        });
      print(index);
    }

    double percentage1Calculate() {
      int wouldClick = 12;
      int ratherClick = 13;
      double percentage1 = wouldClick / (wouldClick + ratherClick) * 100;
      return percentage1;
    }

    double percentage2Calculate() {
      int wouldClick = 2;
      int ratherClick = 3;
      double percentage2 = ratherClick / (wouldClick + ratherClick) * 100;
      return percentage2;
    }

    void percengtageTrigger(){
      setState(() {
        shouldShow = true;
      });
      Timer timer = Timer(Duration(milliseconds: 1350), () {
        setState(() {
          shouldShow = false;
        });
      });
    }

    final PrimaryColor = const Color(0xff404040);

    final PreferredSizeWidget appBar = AppBar(
      centerTitle: true,
      title: Text(
        'Would you Rather',
        style: TextStyle(fontFamily: 'FredokaOne'),
      ),
      backgroundColor: PrimaryColor,
    );
    double stackHeight = (MediaQuery.of(context).size.height -
        appBar.preferredSize.height -
        MediaQuery.of(context).padding.top);
    double stackWidth = MediaQuery.of(context).size.width;
    return Scaffold(
        backgroundColor: Color(0xff404040),
        appBar: appBar,


        body: Stack(
          children: [
            GestureDetector(
              onTap: () {
                percengtageTrigger();
              },
              child: Container(
                height: stackHeight * 0.5,
                width: stackWidth,
                color: Colors.blue,
                child: Column(
                  children: <Widget>[
                    shouldShow
                        ? Container(
                        padding: const EdgeInsets.only(top: 10, right: 10),
                        height: stackHeight * 0.1,
                        color: Colors.blue,
                        width: double.infinity,
                        child: Column(
                          mainAxisSize: MainAxisSize.max,
                          crossAxisAlignment: CrossAxisAlignment.end,
                          children: <Widget>[
                            Text(
                              '${percentage1Calculate().toStringAsFixed(0)}%',
                              style: TextStyle(
                                color: Colors.white,
                                fontSize: 23,
                                fontFamily: 'NewsCycle',
                              ),
                            ),
                          ],
                        ))
                        : Container(
                      height: stackHeight * 0.1,
                      color: Colors.blue,
                      width: double.infinity,
                    ),
                    Container(
                        color: Colors.blue,
                        height: stackHeight * 0.4,
                        width: double.infinity,
                        child: Column(
                          children: <Widget>[
                            Padding(
                              padding: const EdgeInsets.only(top: 20),
                              child: Text(
                                _questions[index].would, //here its showing error 
                                style: TextStyle(
                                  color: Colors.white,
                                  fontSize: 23,
                                  fontFamily: 'NewsCycle',
                                ),
                              ),
                            ),
                          ],
                        )),
                  ],
                ),
              ),
            ),
            GestureDetector(
              onTap: () {
                percengtageTrigger();
              },
              child: Align(
                alignment: Alignment.bottomCenter,
                child: Container(
                  height: stackHeight * 0.5,
                  width: stackWidth,
                  color: Colors.red,
                  child: Column(
                    children: <Widget>[
                      shouldShow
                          ? Container(
                          padding:
                          const EdgeInsets.only(top: 10, right: 10),
                          height: stackHeight * 0.1,
                          color: Colors.red,
                          width: double.infinity,
                          child: Column(
                            mainAxisSize: MainAxisSize.max,
                            crossAxisAlignment: CrossAxisAlignment.end,
                            children: <Widget>[
                              Text(
                                '${percentage2Calculate().toStringAsFixed(0)}%',
                                style: TextStyle(
                                  color: Colors.white,
                                  fontSize: 23,
                                  fontFamily: 'NewsCycle',
                                ),
                              ),
                            ],
                          ))
                          : Container(
                        height: stackHeight * 0.1,
                        color: Colors.red,
                        width: double.infinity,
                      ),
                      Container(
                          color: Colors.red,
                          height: stackHeight * 0.4,
                          width: double.infinity,
                          child: Column(
                            children: <Widget>[
                              Padding(
                                padding: const EdgeInsets.only(top: 40),
                                child: Text(
                                  _questions[index].rather,
                                  style: TextStyle(
                                    color: Colors.white,
                                    fontSize: 23,
                                    fontFamily: 'NewsCycle',
                                  ),
                                ),
                              ),
                            ],
                          )),
                    ],
                  ),
                ),
              ),
            ),
            Align(
              alignment: Alignment.center,
              child: Container(
                width: stackWidth,
                height: stackHeight * 0.015,
                color: Color(0xff404040),
              ),
            ),
            Align(
              alignment: Alignment.center,
              child: Container(
                  width: stackWidth,
                  height: stackHeight * 0.15,
                  decoration: BoxDecoration(
                    shape: BoxShape.circle,
                    color: Color(0xff404040),
                  ),
                  child: Align(
                    alignment: Alignment.center,
                    child: GestureDetector(
                      onTap: () {
                        nextQuestion();
                      },
                      child: Text(
                        "SKIP",
                        style: TextStyle(
                            color: Colors.white,
                            fontFamily: 'FredokaOne',
                            fontSize: 27),
                      ),
                    ),
                  )),
            ),
          ],
        ));
  }
}

还要在显示错误的代码中注释。我不知道如何解决它,但我认为问题是因为在调用索引数据之前未加载 API 数据?

尝试使用 Futurebuild 函数,但它只是继续加载函数并显示指示器,当它在 termail 中加载时不显示容器,它继续将值打印为无限循环。

 class _MyHomePageState extends State<MyHomePage> {
  bool showApp = false;
  var _questions = new List<Questions>();

  Future<List> _getQuestions() async {
    final response = await API.getUsers();
    setState(() {
      Iterable list = json.decode(response.body);
      print(list);
      print(list);
      _questions = list.map((model) => Questions.fromJson(model)).toList();
      print(_questions);
      showApp = true;
    });
    return Future.value(_questions);
  }

  int index = 0;
  bool shouldShow = false;

  @override
  Widget build(BuildContext context) {
    int size = _questions?.length;

    void nextQuestion() {
      if (index < size - 1)
        setState(() {
          index++;
        });
      print(index);
    }

    double percentage1Calculate() {
      int wouldClick = 12;
      int ratherClick = 13;
      double percentage1 = wouldClick / (wouldClick + ratherClick) * 100;
      return percentage1;
    }

    double percentage2Calculate() {
      int wouldClick = 2;
      int ratherClick = 3;
      double percentage2 = ratherClick / (wouldClick + ratherClick) * 100;
      return percentage2;
    }

    void percengtageTrigger() {
      setState(() {
        shouldShow = true;
      });
      Timer timer = Timer(Duration(milliseconds: 1350), () {
        setState(() {
          shouldShow = false;
        });
      });
    }

    final PrimaryColor = const Color(0xff404040);

    final PreferredSizeWidget appBar = AppBar(
      centerTitle: true,
      title: Text(
        'Would you Rather',
        style: TextStyle(fontFamily: 'FredokaOne'),
      ),
      backgroundColor: PrimaryColor,
    );
    double stackHeight = (MediaQuery.of(context).size.height -
        appBar.preferredSize.height -
        MediaQuery.of(context).padding.top);
    double stackWidth = MediaQuery.of(context).size.width;
    return FutureBuilder(
        initialData: null, //initial default data if you have some
        future: _getQuestions(),
        builder: (BuildContext context,
            AsyncSnapshot<List> snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            if (snapshot.hasData) {
              print("Data found, You can continue");
              return Center(child: Text('Datafound'));
            } else if (snapshot.hasError) {
              return Center(child: Text('HaSError'));
            }
          } else {
            print("loading");
            return CircularProgressIndicator();
          }
        });
  }
}

标签: flutterdart

解决方案


问题似乎是您所怀疑的。在构建方法开始执行之前数据不可用,因此我们遇到了超出范围的错误。这个问题的解决方案是在你的构建方法中使用FutureBuilder 。

不要在 initState 中获取数据,而是将代码包装在您的构建方法中并将FutureBuilder设置getUser()为. 看看下面的代码片段futureFutureBuilder

@override
  Widget build(BuildContext context) {
    return FutureBuilder(
        initialData:null //initial default data if you have some
        future: API.getUsers(),
        builder:(BuildContext context,AsyncSnapshot snapshot){
            if(snapshot.ConnectionState==ConnectionState.none||snapshot.ConnectionState==ConnectionState.waiting){
                print("data has not been fetched yet");
                return CircularProgressIndicator();
            }
            else{
             if(snapshot.hasData){
                 print("Data found, You can continue");
                 //decode your json here and initialize the variables you need
                 return Scaffold(
                     // your widgets
                 );
             }else{
                 print("No data found");
                 return Text("No data found");
             }
            }
        }
    );
}

在你的情况下,你会做这样的事情

import 'package:flutter/material.dart';

class _MyHomePageState extends State<MyHomePage> {
  bool showApp = false;
  var _questions = new List<Questions>();

  // Future<List> _getQuestions() async {
  //   final response = await API.getUsers();
  //   setState(() {
  //     Iterable list = json.decode(response.body);
  //     print(list);
  //     print(list);
  //     _questions = list.map((model) => Questions.fromJson(model)).toList();
  //     print(_questions);
  //     showApp = true;
  //   });
  //   return Future.value(_questions);
  // }

  int index = 0;
  bool shouldShow = false;

  @override
  Widget build(BuildContext context) {
    int size = _questions?.length;

    void nextQuestion() {
      if (index < size - 1)
        setState(() {
          index++;
        });
      print(index);
    }

    double percentage1Calculate() {
      int wouldClick = 12;
      int ratherClick = 13;
      double percentage1 = wouldClick / (wouldClick + ratherClick) * 100;
      return percentage1;
    }

    double percentage2Calculate() {
      int wouldClick = 2;
      int ratherClick = 3;
      double percentage2 = ratherClick / (wouldClick + ratherClick) * 100;
      return percentage2;
    }

    void percengtageTrigger() {
      setState(() {
        shouldShow = true;
      });
      Timer timer = Timer(Duration(milliseconds: 1350), () {
        setState(() {
          shouldShow = false;
        });
      });
    }

    final PrimaryColor = const Color(0xff404040);

    final PreferredSizeWidget appBar = AppBar(
      centerTitle: true,
      title: Text(
        'Would you Rather',
        style: TextStyle(fontFamily: 'FredokaOne'),
      ),
      backgroundColor: PrimaryColor,
    );
    double stackHeight = (MediaQuery.of(context).size.height -
        appBar.preferredSize.height -
        MediaQuery.of(context).padding.top);
    double stackWidth = MediaQuery.of(context).size.width;
    return FutureBuilder(
        initialData: null, //initial default data if you have some
        future: API.getUsers(),
        builder: (BuildContext context, AsyncSnapshot<List> snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            if (snapshot.hasData) {
              var response  = snapshot.data;
              print("Data found, You can continue");
              Iterable list = json.decode(response.body);
              print(list);
              print(list);
              _questions =
                  list.map((model) => Questions.fromJson(model)).toList();
              print(_questions);
              showApp = true;
              return Center(child: Text('Datafound'));
            } else if (snapshot.hasError) {
              return Center(child: Text('HaSError'));
            }
          } else {
            print("loading");
            return CircularProgressIndicator();
          }
        });
  }
}


推荐阅读