Флаттер инициализации объекта из firestore перед сборкой виджета - PullRequest
0 голосов
/ 29 апреля 2020

Я новичок в трепетании и создаю приложение, которое создает проекты. Я работаю над страницей проекта просмотра, которая позволяет пользователю просматривать каждый вопрос. То, как он настроен, позволяет пользователю просмотреть вопрос, а затем нажать «Далее» (оставаясь на той же странице), чтобы просмотреть следующий вопрос. Первый initState инициализирует объект Project. Этот объект проекта затем должен go получить данные / информацию из документа. Вопросы хранятся в виде списка объектов «Вопрос», где у каждого объекта есть тип (текст, множественный выбор, цифры c, загрузка фотографий и т. Д. c), вопрос и номер. Тип вопроса используется для определения того, какой виджет отображать (например, загрузка фотографий будет отличаться от ввода текста).

Проблема, с которой я столкнулся, заключается в том, что объект проекта инициализирован, а список объектов вопроса - нет, и я получаю ошибки индексации. Однако, когда я горячо refre sh, я вижу правильный виджет (в настоящее время просто текст). Другая проблема, которая, я думаю, связана, заключается в том, что каждый раз, когда пользователь нажимает кнопку «Далее», объект переходит и снова получает все вопросы, поэтому список никогда не заканчивается. Я считаю, что проблема заключается в моих функциях getdataFromProject и questionData () в getproject.dart (первый фрагмент кода).

Я пытался использовать будущего строителя, но я не уверен, что это правильное решение. Однако моя сборка зависит от объекта, который будет завершен. Поэтому я попытался использовать переменную Future projectFuture и установить ее равной моей функции _getQuestions () (вызываемой в initState ()).

Любая помощь приветствуется.

class Questions {
  final String question;
  final String number;
  final String type;
  Questions({this.question, this.number, this.type});
  List<String> answers = new List();
}

class GetProject {
//this is what keeps growing each time next is pressed
List<Questions> questions; //holds the question objects 
  String docID;
   String title;
  GetProject(String title, String docID){
    this.docID = docID;
    this.title=title;
  questionData();

  } 





  Future<void> get getdataFromProject async {
    return await questionData();
  }



  Future<void> questionData() async {

    int count = 0;

  Future<DocumentSnapshot> snapshot =
        Firestore.instance.collection('Projects').document(this.docID).get();


    return await snapshot.then((DocumentSnapshot questionSnap) => {
          questionSnap.data.forEach((key, value) {
            if ('$key' == 'count') {
              count = value;
              count--;
              //returncount=count;
            } else if ('$key' == ('Question' + count.toString())) {
              print(value['Type']);
              Questions question = new Questions(
                type: value['Type'],
                number: value['Number'],
                question: value['Question'],
              );
              if (value['Type'] == 'MultipleChoice') {
                value['Answers'].forEach((e) {
                  question.answers.add(e.toString());
                });
                //question.answers.addAll(value['Answers']);
              }
              questions.add(question);

              count--;
            }
          }),
        });

  }


 int getType(int index) {
    switch (questions[index].type) {
      case 'TextInputItem':
        return 0;
      case 'MultipleChoice':
        return 1;
      case 'ShortAnswerItem':
        return 2;
      case 'UserLocation':
        return 3; 
    }
    return -1;
  }
class ViewProject extends StatefulWidget {
  final String docIDref;
  final String title;
  ViewProject({this.docIDref, this.title});

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

class _ViewProjectState extends State<ViewProject> {
  GetProject project;
  int _currentQuestion = 0;
  Future projectFuture;


  int _getType(_currentQuestion) {
    switch(project.questions[_currentQuestion].type){
      case 'TextInputItem':
        return 0;
      case 'MultipleChoice':
        return 1;
      case 'ShortAnswerItem':
        return 2;
      case 'UserLocation':
        return 3; 
    }
    return -1;
  }

Widget build(BuildContext context) {

  return new MaterialApp(

      home: new Scaffold(
          appBar: AppBar(title: Text("Random Widget")),
          body: 
          project.questions.length == 0

         ? Center(child: CircularProgressIndicator()


         )
         :
          Center(child:

          FutureBuilder(
              initialData: 0,
              future: projectFuture,
              builder: (context, snapshot) {


                if(project.questions.length>0){
                  return getQuestionWidget();
               }
              else{

                  return CircularProgressIndicator();
               }
              }
          )
      )),
    );
}


   Widget getQuestionWidget() {

    switch(_getType(_currentQuestion++)){
      case 0:
        return Column(children: <Widget>[
          Text("TextInputItem", textScaleFactor: 4),
          getNextButton()
        ]);
        break;
      case 1:
        return Column(children: <Widget>[
          Text("MultipleChoice", textScaleFactor: 4),
          getNextButton()
        ]);
        break;
      case 2:
        return Column(children: <Widget>[
          Text("ShortAnswer", textScaleFactor: 4),
          getNextButton()
        ]);
        break;
      case 3:
        return Column(children: <Widget>[
          Text("UserLocation", textScaleFactor: 4),
          getNextButton()
        ]);
        break;
      case -1:
        return Column(children: <Widget>[
          Text("Submit Page", textScaleFactor: 4),
          //getNextButton()
        ]);
    }
  }


Widget getNextButton(){
      return RaisedButton(
          child: Text("NEXT"),
          color: Colors.red,
          onPressed: () {
            if(_currentQuestion < project.questions.length){
                return getQuestionWidget();
            }
            return Text("All done!"); 
            //setState(() {

              //_currentQuestion++;
              //return getQuestionWidget();

              //_getType(_currentQuestion);
           // });

          }
      );
  }

  @override
  void initState() {
    project = new GetProject(widget.title, widget.docIDref);
    //project.getdataFromProject();
    //_getQuestions();
    projectFuture=_getQuestions();
    super.initState();

  }

  Future<void> _getQuestions() async {

    return await project.getdataFromProject;


  }

  // Call this function when you want to move to the next page
  void goToNextPage() {

      _currentQuestion++;

  }


}

1 Ответ

0 голосов
/ 29 апреля 2020

Я обычно загружаю фьючерсы в методе didChangeDependencies.

что-то вроде: -

@override
didChangeDependencies() { 
   if (this.asyncdata == null) 
        loadData();
}

Future<void> loadData() async {
    this.asyncdata = await someAsyncFuntionThatReturnsData();
}

Это должно помочь. В день нажатия кнопки всегда легче загружать вещи, поскольку их функции могут быть асинхронными c фьючерсами, но вышеупомянутый шаблон должен решить двойную загрузку с помощью if.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...