无法在Flutter中的Future中存储空值< CustomModel>

e1xvtsh3  于 2023-06-30  发布在  Flutter
关注(0)|答案(3)|浏览(148)

我有一个变量late Future<QuestionModel> question;和一个获取QuestionModel的函数

fetchQuestion(){
    // Question model is initialised here
}

它正在生成中用于显示UI

FutureBuilder(
              future: question,
              builder: (context, snapshot) {
                if (snapshot.data == null) {
                  return LoadingWidget(
                    height: 200,
                    width: 200,
                  );
                }
                if (snapshot.hasError) {
                  return Text("Something went wrong");
                }

                QuestionModel question = snapshot.data as QuestionModel;
                return Container(),
                  );
                }
            ),

它运行良好。
在UI本身,我有一个按钮,它发送数据到后端,并从Firestore获取新的QuestionModel。它也很好用。
要求:点击按钮后显示加载屏幕,避免重新点击,直到获取新的QuestionModel,但我不想为此创建单独的isLoading变量。
我只是想重置questionModel,它之前被初始化为questionModel = null,并通过使用futurebuilder本身来显示加载屏幕,因为我已经将LoadingWidget连接到了我的FutureBuilder。但这是不可能的,因为Future不能为null,错误如下

A value of type 'Null' can't be assigned to a variable of type 'Future<QuestionModel>'.

编辑2:换句话说,我想取消初始化future,以触发Future构建器显示正在加载Widget。

omtl5h9j

omtl5h9j1#

尝试此处的演示以了解更多信息

https://dartpad.dev/?id=3dadbc210baaf70d405b75e5389c7ba8

您可以使用setState来重建FutureBuilder
但是,当您将FutureBuilder定义为local state variable时,FutureBuilder将不会执行future方法
解决方案:

  • 将Future方法定义为非状态变量。你可以在任何文件上写。例如在您的helper.dart
Future<String> apiCall() async {
  print("apiCall is executed...");
  await Future.delayed(const Duration(seconds: 3));
  return Future.value("${Random().nextInt(100)} update");
}

然后在FutureBuilder小部件中,使用ConnectionState.waiting的条件,
每次你调用setStateapiCall就会被执行

FutureBuilder(
      future: localFuture,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const Center(child: CircularProgressIndicator());
        } else {
          return Text("${snapshot.data}");
        }
      })

ps:如果你使用snapshot.hasData,它将是true即使apiCall还没有完成.更好地了解连接状态。

sg3maiej

sg3maiej2#

将声明更改为:late Future<QuestionModel>? question;
将代码更改为:

FutureBuilder(
              future: question,
              builder: (context, snapshot) {
                if (snapshot.data == null) {
                  return LoadingWidget(
                    height: 200,
                    width: 200,
                  );
                }
                if (snapshot.hasError) {
                  return Text("Something went wrong");
                }

                QuestionModel? question = snapshot.data as QuestionModel;
                return Container(),
                  );
                }
            ),
nhjlsmyf

nhjlsmyf3#

你可以试试这个:(由于FutureBuilder每次调用setState时都会进行重建,因此我们不应该使用它。
1.将QuestionModel声明为可空变量

QuestionModel? question

1.创建函数来获取问题,例如:

void _loadData() {
    setState(() {
      question = null;
    });
    Future.delayed(Duration(seconds: 1), () async {
      var questionResult = await your_service.fecthQuestion(); // Your defined function to fetch the question
      question = questionResult;
      setState(() {});
    });
  }

1.在initState内部调用它

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

1.您可以创建如下所示的小部件

Widget _buildBody() {
    if (question == null) {
      return Center(child: CircularProgressIndicator());
    }

    return Center(child: Text('My Widget'));
  }

1.最后但并非最不重要的是,您可以通过调用_loadData()来获取按钮单击时的新问题,屏幕将显示加载,直到问题被成功获取。

相关问题