首页 > 解决方案 > 未来的建设者没有捕捉到异常

问题描述

我试图在颤动中发出一个简单的 POST 请求并尝试捕获异常。我在控制台中看到异常,但是当我在 FutureBuilder 中执行 print(snapshot.hasError) 时,它给了我错误。

因为,我是新来的,我不知道我错过了哪一部分。现在被困在这里一段时间了。

这是我在 service.dart 中的 post 功能

Future <dynamic> postData(String url, dynamic data) async {

    try {
      final response = await post(_baseUrl + url, body: data);
      if (response.statusCode == 200) {
        return json.decode(response.body);
      } else {
        throw Exception('Failed to load data');
      }
    } catch (e) {
      throw Exception(e);
    }
  }

在我的 UI 设计课程中,我首先设置了显示输入文本字段(姓名和电子邮件)的条件,一旦用户填写了他的输入详细信息,我将显示 FutureBuilder 小部件。

import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

import 'package:stationary/components/error_dialog.dart';
import 'package:stationary/services/base_helper.dart';
import 'package:stationary/services/signup_services.dart';
import 'package:stationary/size_config.dart';
import 'package:stationary/components/spacer.dart';

import '../../constants.dart' as Constants;

class InputUserDetails extends StatefulWidget {

  // final String userMobile;

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

class _InputUserDetailsState extends State<InputUserDetails> {

  TextEditingController nameController = TextEditingController();
  TextEditingController emailController = TextEditingController();

  bool isButtonDisabled = true;
  bool showLoader = false;

  Future<dynamic> futureList;

  final storage = new FlutterSecureStorage();

  String _mobileNum;

  void checkButtonDisability(value) {
    var name = nameController.text;
    var email = emailController.text;
    if (name.length > 0 && email.length > 0) {
      setState(() {
        isButtonDisabled = false;
      });
    } else {
      setState(() {
        isButtonDisabled = true;
      });
    }
  }
  
  @override
  void initState() {
    super.initState();
    _getMobileNumber();
  }

  _getMobileNumber() async {
    var tempMobileNum = await storage.read(key: 'userMobile');
    setState(() {
      _mobileNum = tempMobileNum;
    });
  }

  signUpUser(name, email) async {
    String endpoint = Constants.postUserInfo;
    var json = {
      "email": email,
      "name": name,
      "phone_number": _mobileNum
    };
    print(json);
    futureList = await ApiBaseHelper().postData(endpoint, json);
  }

  @override
  Widget build(BuildContext context) {
    SizeConfig().init(context);
    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: showLoader? FutureBuilder(
        future: futureList,
        builder: (context, snapshot) {
          // print(snapshot.hasData); // ================= false
          // print(snapshot.hasError); // ================ false

          if(snapshot.hasData) {
            print(snapshot.data);
            return Container();
          } else if(snapshot.hasError) {
            print(snapshot.error);
            return ErrorDialog('Some error occurred');
          }
          return CircularProgressIndicator();
        },
      ) : Container(
        margin: EdgeInsets.all(SizeConfig.safeBlockHorizontal * 5),
        child: SingleChildScrollView(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              SizedBox(
                height: SizeConfig.safeBlockVertical * 10,
              ),

              Container(
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    Text(
                      'Enter your details',
                      style: TextStyle(
                        fontWeight: FontWeight.w500,
                        fontFamily: 'Roboto',
                        fontSize: SizeConfig.safeBlockHorizontal * 5,
                        color: Colors.white,
                      ),
                    ),

                    Container(
                      child: SpacerElement(),
                    ),
                  ],
                ),
              ),

              SizedBox(
                height: SizeConfig.safeBlockVertical * 2,
              ),

              SizedBox(height: SizeConfig.safeBlockVertical * 10, ),

              Flexible(
                child: TextFormField(
                  style: TextStyle(
                    fontWeight: FontWeight.w500,
                    fontFamily: 'Roboto',
                    fontSize: SizeConfig.safeBlockHorizontal * 4,
                    color: Colors.white,
                  ),
                  onChanged: (value) {
                    checkButtonDisability(value);
                  },
                  cursorColor: Colors.white,
                  controller: nameController,
                  keyboardType: TextInputType.text,
                  decoration: new InputDecoration(
                    hintText: 'Enter Your Name',
                    hintStyle: TextStyle(
                      color: Colors.white30,
                      fontFamily: 'Roboto',
                      fontWeight: FontWeight.w400,
                    ),
                    contentPadding: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
                    isDense: true,
                    border: InputBorder.none,
                    focusedBorder: InputBorder.none,
                    enabledBorder: InputBorder.none,
                    errorBorder: InputBorder.none,
                    disabledBorder: InputBorder.none,
                  ),
                ),
              ),

              SizedBox(height: SizeConfig.safeBlockVertical * 5, ),

              Flexible(
                child: TextFormField(
                  style: TextStyle(
                    fontWeight: FontWeight.w500,
                    fontFamily: 'Roboto',
                    fontSize: SizeConfig.safeBlockHorizontal * 4,
                    color: Colors.white,
                  ),
                  onChanged: (value) {
                    checkButtonDisability(value);
                  },
                  cursorColor: Colors.white,
                  controller: emailController,
                  keyboardType: TextInputType.emailAddress,
                  decoration: new InputDecoration(
                    hintText: 'Enter Your Email',
                    hintStyle: TextStyle(
                      color: Colors.white30,
                      fontFamily: 'Roboto',
                      fontWeight: FontWeight.w400,
                    ),
                    contentPadding: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
                    isDense: true,
                    border: InputBorder.none,
                    focusedBorder: InputBorder.none,
                    enabledBorder: InputBorder.none,
                    errorBorder: InputBorder.none,
                    disabledBorder: InputBorder.none,
                  ),
                ),
              ),

              SizedBox(height: SizeConfig.safeBlockVertical * 5, ),

              Container(
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(50),
                ),
                child: FlatButton(
                  padding: EdgeInsets.symmetric(
                    horizontal: SizeConfig.safeBlockHorizontal * 5,
                    vertical: SizeConfig.safeBlockVertical * 2
                  ),
                  color: isButtonDisabled ? Theme.of(context).primaryColor : Theme.of(context).buttonColor,
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(5.0),
                  ),
                  onPressed: isButtonDisabled? () {} : () {
                    var email = emailController.text;
                    var name = nameController.text;
                    var flag = RegExp(r"^[a-zA-Z0-9.]+@[a-zA-Z0-9]+\.[a-zA-Z]+").hasMatch(email);
                    if(!flag) {
                      showDialog(context: context, child: ErrorDialog('Please enter a valid email'));
                    } else {
                      setState(() {
                        showLoader = true;
                      });
                      signUpUser(name, email);
                    }
                    // Navigator.push(context, MaterialPageRoute(builder: (context) => SearchMapsScreen()));
                  },
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Text(
                        'TAKE ME IN',
                        style: TextStyle(
                          fontWeight: FontWeight.w500,
                          fontFamily: 'Roboto',
                          color: isButtonDisabled ? Colors.white60 : Colors.black,
                          fontSize: SizeConfig.safeBlockHorizontal * 4,
                        ),
                      ),
                    ],
                  ),
                ),
              ),

            ],
          ),
        ),
      ),
    );
  }
}

请建议我在哪里遗漏了什么,以及这是否是使用输入文本处理 Future Builder 小部件和 Column 小部件的正确方法。

任何帮助,将不胜感激。

提前致谢!

标签: flutterexceptionflutter-http

解决方案


问题在于逻辑上onPressed

else {
  setState(() {
     showLoader = true;
  });
  signUpUser(name, email);
}

showLoader您在运行该方法之前更改了 的值signUpUser,因此当 setState 更改时FutureBuilder,futurefutureList为 null (尚未声明),我认为您可以使该方法同步,因为您说futureList它将持有 a Future,所以有没有理由让它异步/等待

signUpUser(name, email) {
    String endpoint = Constants.postUserInfo;
    var json = {
      "email": email,
      "name": name,
      "phone_number": _mobileNum
    };
    print(json);
    futureList = ApiBaseHelper().postData(endpoint, json); //This is fine, both sides are of type Future<dynamic>
  }

并在 setState 之前运行它,因此在运行之前futureList不引用空值FutureBuilder


推荐阅读