Home > Software design >  RangeError (index): Invalid value: Not in inclusive range 0..2 3
RangeError (index): Invalid value: Not in inclusive range 0..2 3

Time:12-15

I built a simple quiz app with 3 questions, the logic works and it takes you through all the questions. At the end there is an alert dialog that pops up and shows you your score, after clicking close it resets the quiz and allows you to play again.

I am now getting an error when the alert dialog pops up that says

RangeError (index): Invalid value: Not in inclusive range 0..2 3

Please help with this.

Here is my code for the app

import 'package:flutter/material.dart';

void main() => runApp(const QuizApp());

class QuizApp extends StatelessWidget {
  const QuizApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Quiz Game',
      home: QuizPage(),
    );
  }
}

class QuizPage extends StatefulWidget {
  const QuizPage({super.key});

  @override
  _QuizPageState createState() => _QuizPageState();
}

class _QuizPageState extends State<QuizPage> {
  int _currentQuestion = 0;
  int _score = 0;

  final List<Map<String, Object>> _questions = [
    {
      'question': 'What is the capital of France?',
      'answers': [
        {'text': 'Paris', 'correct': true},
        {'text': 'London', 'correct': false},
        {'text': 'Berlin', 'correct': false},
      ],
    },
    {
      'question': 'Is this app useful?',
      'answers': [
        {'text': 'Yes', 'correct': true},
        {'text': 'No', 'correct': false},
      ],
    },
    {
      'question': 'Is this app fun?',
      'answers': [
        {'text': 'Yes', 'correct': true},
        {'text': 'No', 'correct': false},
        {'text': 'Maybe', 'correct': false},
      ],
    },
  ];

  @override
  Widget build(BuildContext context) {
    // Get the current question and answers
    final Map<String, Object> currentQuestion = _questions[_currentQuestion];
    final String question = currentQuestion['question'] as String;
    final List<Map<String, Object>> answers =
        currentQuestion['answers'] as List<Map<String, Object>>;

    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // Display the current question
            Text(
              question,
              style: Theme.of(context).textTheme.headline3,
            ),
            const SizedBox(height: 20),

            // Display the answer buttons
            ...answers.map((Map<String, Object> answer) {
              return TextButton(
                child: Text(answer['text'] as String),
                onPressed: () => _answerQuestion(answer['correct'] as bool),
              );
            }),
          ],
        ),
      ),
    );
  }

  void _answerQuestion(bool isCorrect) {
    if (isCorrect) {
      _score  ;
    }

    setState(() {
      _currentQuestion  ;

      // Check if we have reached the end of the quiz
      if (_currentQuestion >= _questions.length) {
        // Show a dialog with the final score
        showDialog(
          context: context,
          builder: (BuildContext context) {
            return AlertDialog(
              title: const Text('Quiz Finished'),
              content: Text('You scored $_score points'),
              actions: [
                TextButton(
                  child: const Text('Close'),
                  onPressed: () {
                    // Reset the quiz
                    setState(() {
                      _currentQuestion = 0;
                      _score = 0;
                    });
                    Navigator.of(context).pop();
                  },
                ),
              ],
            );
          },
        );
      }
    });
  }
}

CodePudding user response:

In this case, the error is because _currentQuestion is incremented in setState. Changing its value in setState will cause build to run again with the new value. This means that the expression _questions[_currentQuestion] will be evaluated. Since _questions is a List with 3 objects, the valid values for _currentQuestion are 0, 1, or 2. Once you increment _currentQuestion to 3, that is out of the range of valid values. So Dart responds with the error you are seeing.

Try moving your increment logic out of setState, and only call setState if _currentQuestion has a valid value.

CodePudding user response:

I've changed your _answerQuestion function a bit. I think is a good idea to await showDialog since it is a async call. Then removed unnecessary setState calls. Root of the problem was explained by @pmich16 and I just did the coding.

void _answerQuestion(bool isCorrect) async {
    if (isCorrect) {
      _score  ;
    }
    // Check if we have reached the end of the quiz
    if (_currentQuestion >= (_questions.length - 1)) {
      // Show a dialog with the final score
      await showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            title: const Text('Quiz Finished'),
            content: Text('You scored $_score points'),
            actions: [
              TextButton(
                child: const Text('Close'),
                onPressed: () {
                  // Reset the quiz
                  setState(() {
                    _currentQuestion = 0;
                    _score = 0;
                  });
                  Navigator.of(context).pop();
                },
              ),
            ],
          );
        },
      );
    } else {
      setState(() {
        _currentQuestion  ;
      });
    }
  }
  • Related