1

我正在尝试构建一个测验应用程序。当任何用户开始参与测验时,计时器就会启动,并且不知道为什么每秒钟都会重新初始化所有内容。布尔参数“已回答”每秒都设置为 false。结果,参与者可以多次回答相同的问题,这会导致错误的结果并且不会发生。这是一个片段-

class MathQuizPlay extends StatefulWidget {
  final String quizId;
  MathQuizPlay({Key key, this.quizId}) : super(key: key);

  @override
  _MathQuizPlayState createState() => _MathQuizPlayState(this.quizId);
}

int total = 0;
int _correct = 0;
int _incorrect = 0;
int _notAttempted = 0;
int timer;
String showtimer;

class _MathQuizPlayState extends State<MathQuizPlay> {
  var quizId;
  _MathQuizPlayState(this.quizId);
  QuerySnapshot questionSnapshot;
  bool isLoading = true;

  getQuestionData(String quizId) async {
    return await Firestore.instance
        .collection('math')
        .document(quizId)
        .collection('QNA')
        .getDocuments();
  }

  @override
  void initState() {
    getQuestionData(quizId).then((value) {
      questionSnapshot = value;
      setState(() {
        total = questionSnapshot.documents.length;
        _correct = 0;
        _incorrect = 0;
        _notAttempted = questionSnapshot.documents.length;
        isLoading = false;
        timer = total * 15;
        showtimer = timer.toString();
      });
    });

    starttimer();
    super.initState();
  }

  @override
  void setState(fn) {
    if (mounted) {
      super.setState(fn);
    }
  }

  Questions getQuestionModelFromDatasnapshot(
      DocumentSnapshot questionSnapshot) {
    final Questions questionModel = Questions(
        question: questionSnapshot.data['question'],
        option1: questionSnapshot.data['option1'],
        option2: questionSnapshot.data['option2'],
        option3: questionSnapshot.data['option3'],
        option4: questionSnapshot.data['option4'],
        correctOption: questionSnapshot.data['correctOption'],
        answered: false);

    return questionModel;
  }

  void starttimer() async {
    const onesec = Duration(seconds: 1);
    Timer.periodic(onesec, (Timer t) {
      setState(() {
        if (timer < 1) {
          t.cancel();
          Navigator.pushReplacement(
              context,
              MaterialPageRoute(
                  builder: (context) => Result(
                        correct: _correct,
                        incorrect: _incorrect,
                        total: total,
                        notattempt: _notAttempted,
                        collection: 'math',
                        quizId: quizId,
                      )));
        } else {
          timer = timer - 1;
        }
        showtimer = timer.toString();
      });
    });
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.teal[300],
        title: Text("Questions",
            style: TextStyle(
              color: Colors.white,
            )),
        elevation: 5.0,
        centerTitle: true,
      ),
      body: isLoading
          ? Container(
              child: Center(child: CircularProgressIndicator()),
            )
          : SingleChildScrollView(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  SizedBox(
                    height: 10,
                  ),
                  Center(
                      child: Container(
                          height: 60,
                          width: 60,
                          decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(36),
                            border: Border.all(
                              width: 2.0,
                              color: Colors.red.withOpacity(0.8),
                            ),
                          ),
                          child: Center(
                              child: Text(
                            showtimer,
                            style: TextStyle(
                                fontWeight: FontWeight.w500,
                                fontSize: 19.0,
                                color: Colors.red.withOpacity(0.8)),
                          )))),
                  SizedBox(
                    height: 10,
                  ),
                  Center(child: Text('Tap on the option to select answer')),
                  SizedBox(
                    height: 10,
                  ),
                  questionSnapshot.documents == null
                      ? Container(
                          child: Center(
                            child: Text("No Data"),
                          ),
                        )
                      : ListView.builder(
                          itemCount: questionSnapshot.documents.length,
                          shrinkWrap: true,
                          physics: ClampingScrollPhysics(),
                          itemBuilder: (context, index) {
                            return Padding(
                              padding: const EdgeInsets.symmetric(
                                  vertical: 15.0, horizontal: 25),
                              child: QuizPlayTile(
                                questionModel: getQuestionModelFromDatasnapshot(
                                    questionSnapshot.documents[index]),
                                index: index,
                              ),
                            );
                          }),
                  SizedBox(
                    height: 30,
                  ),
                  Center(
                    child: RaisedButton(
                        padding:
                            EdgeInsets.symmetric(vertical: 18, horizontal: 60),
                        color: Colors.teal[300],
                        textColor: Colors.white,
                        shape: RoundedRectangleBorder(
                            borderRadius: new BorderRadius.circular(8.0)),
                        child: Text(
                          'Submit',
                          style: TextStyle(fontSize: 16),
                        ),
                        elevation: 7.0,
                        onPressed: () {
                          Navigator.pushReplacement(
                              context,
                              MaterialPageRoute(
                                  builder: (context) => Result(
                                        correct: _correct,
                                        incorrect: _incorrect,
                                        total: total,
                                        notattempt: _notAttempted,
                                        collection: 'math',
                                        quizId: quizId,
                                      )));
                        }),
                  ),
                  SizedBox(
                    height: 50,
                  )
                ],
              ),
            ),
    );
  }
}


4

2 回答 2

1

问题 :

当您每次计时器完成一秒钟时都调用 setState .... 它每秒刷新一次屏幕。因此,在每一秒重建该函数内的每一行代码之后,都会重新调用构建函数。现在主要问题是函数:'getQuestionModelFromDatasnapshot' 将始终提供一个新的'questionModel',其'answered' 参数的值为 false,屏幕每刷新一秒。

解决方案 :

现在我有两个解决方案给你:

  1. 良好的编程习惯: 我的猜测是您调用 setState 以每秒钟更新一次 UI 中的计时器值。现在她你必须意识到调用 setState 只是一个小的改变是不好的,因为它会刷新所有其他小部件也将被重新创建,这是不必要的。好的方法是使用 ChangeNotifierProvider,它将在计时器中侦听更新,然后用消费者包装显示计时器值的 UI 文本。因此,每当更新计时器值时......它只会使用计时器值更新 UI 文本。

  2. 如果您想要一个快速的解决方案: 而不是在构建函数中调用“getQuestionModelFromDatasnapshot”方法,您可以做的是将 initstate 中的整个 ListView 初始化为一个变量.... 比如: ListView x = /* 你的 listview 代码包含那个功能 */ ..... 这样做...... 小部件不会每秒重建。

代码有点乱......我强烈希望正确地重新编写代码或使用我在第一个选项中所说的 ChangeNotifierProvider。

于 2020-10-21T20:28:13.580 回答
0

我也无法使用 ChangeNotifierProvider 解决问题。但幸运的是,我找到了一个完全解决我的问题的包。所以我用那个包而不是周期性的 Timer 来设置时间。这是更新-

import 'package:circular_countdown_timer/circular_countdown_timer.dart';

class PhyQuizPlay extends StatefulWidget {
  final String quizId;
  PhyQuizPlay({Key key, this.quizId}) : super(key: key);

  @override
  _PhyQuizPlayState createState() => _PhyQuizPlayState(this.quizId);
}

int total = 0;
int _correct = 0;
int _incorrect = 0;
int _notAttempted = 0;
int timer;

class _PhyQuizPlayState extends State<PhyQuizPlay> {
  var quizId;
  _PhyQuizPlayState(this.quizId);
  QuerySnapshot questionSnapshot;
  bool isLoading = true;

  getQuestionData(String quizId) async {
    return await Firestore.instance
        .collection('physics')
        .document(quizId)
        .collection('QNA')
        .getDocuments();
  }

  @override
  void initState() {
    getQuestionData(quizId).then((value) {
      questionSnapshot = value;
      setState(() {
        total = questionSnapshot.documents.length;
        _correct = 0;
        _incorrect = 0;
        _notAttempted = total;
        isLoading = false;
        timer = total * 15;
      });
    });
    super.initState();
  }

  Questions getQuestionModelFromDatasnapshot(
      DocumentSnapshot questionSnapshot) {
    final Questions questionModel = Questions(
        question: questionSnapshot.data['question'],
        option1: questionSnapshot.data['option1'],
        option2: questionSnapshot.data['option2'],
        option3: questionSnapshot.data['option3'],
        option4: questionSnapshot.data['option4'],
        correctOption: questionSnapshot.data['correctOption'],
        answered: false);

    return questionModel;
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.teal[300],
        title: Text("Questions",
            style: TextStyle(
              color: Colors.white,
            )),
        elevation: 5.0,
        centerTitle: true,
      ),
      body: isLoading
          ? Container(
              child: Center(child: CircularProgressIndicator()),
            )
          : SingleChildScrollView(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  SizedBox(
                    height: 10,
                  ),
                  Center(
                      child: CircularCountDownTimer(
                    width: 80,
                    height: 80,
                    duration: timer,
                    fillColor: Colors.red,
                    color: Colors.white38,
                    isReverse: true,
                    onComplete: () {
                      Navigator.pushReplacement(
                          context,
                          MaterialPageRoute(
                              builder: (context) => Result(
                                    correct: _correct,
                                    incorrect: _incorrect,
                                    total: total,
                                    notattempt: _notAttempted,
                                    collection: 'physics',
                                    quizId: quizId,
                                  )));
                    },
                  )),
                  SizedBox(
                    height: 10,
                  ),
                  Center(child: Text('Tap on the option to select answer')),
                  SizedBox(
                    height: 10,
                  ),
                  questionSnapshot.documents == null
                      ? Center(
                          child: CircularProgressIndicator(),
                        )
                      : ListView.builder(
                          itemCount: questionSnapshot.documents.length,
                          shrinkWrap: true,
                          physics: ClampingScrollPhysics(),
                          itemBuilder: (context, index) {
                            return Padding(
                              padding: const EdgeInsets.symmetric(
                                  vertical: 15.0, horizontal: 25),
                              child: QuizPlayTile(
                                questionModel: getQuestionModelFromDatasnapshot(
                                    questionSnapshot.documents[index]),
                                index: index,
                              ),
                            );
                          }),
                  SizedBox(
                    height: 30,
                  ),
                  Center(
                    child: RaisedButton(
                        padding:
                            EdgeInsets.symmetric(vertical: 18, horizontal: 60),
                        color: Colors.teal[300],
                        textColor: Colors.white,
                        shape: RoundedRectangleBorder(
                            borderRadius: new BorderRadius.circular(8.0)),
                        child: Text(
                          'Submit',
                          style: TextStyle(fontSize: 16),
                        ),
                        elevation: 7.0,
                        onPressed: () {
                          Navigator.pushReplacement(
                              context,
                              MaterialPageRoute(
                                  builder: (context) => Result(
                                        correct: _correct,
                                        incorrect: _incorrect,
                                        total: total,
                                        notattempt: _notAttempted,
                                        collection: 'physics',
                                        quizId: quizId,
                                      )));
                        }),
                  ),
                  SizedBox(
                    height: 50,
                  )
                ],
              ),
            ),
    );
  }
} 

于 2020-10-22T10:33:31.007 回答