在 Flutter 中管理 post 上的错误

Managing errors on post in Flutter

我为我工作的公司做了一个应用程序,该应用程序可以正常工作并解决了一些问题,但是代码很乱,因为我不是正式程序员,这是我的第一个应用程序。现在我正在努力改进代码。

这里的问题是我不知道如何检查 http post 是否成功。

在下面的代码中,您可以看到我做了一些错误处理,但它不能正常工作。 例如,如果应用程序没有从服务器收到 "ok" 消息,它将 return 一个错误,但如果互联网不工作,它不会 return 错误,因为它将永远尝试发送 post。 我想始终检查 post 是否成功并通知用户,或者在尝试一段时间后显示错误(比如 2 秒,我不知道),解决这个问题的最佳方法是什么?

欢迎任何其他改进代码的提示。

    if ((_usuarioController.text.isEmpty) ||
        (_placaController.text.isEmpty) ||
        (_boxController.text.isEmpty) ||
        (dropdownValue1 == "Vehicle type")) {
      Toast.show(
        "\n  Complete all fields  \n",
        context,
        duration: Toast.LENGTH_LONG,
        gravity: Toast.CENTER,
        backgroundRadius: 5.0,
      );
    } else if (_pecasList.length < 1) {
      showDialog(
          context: context,
          builder: (BuildContext context) {
            return AlertDialog(
                title: new Text("Empty List"),
                actions: <Widget>[
                  new FlatButton(
                      child: new Text("Close"),
                      onPressed: () {
                        Navigator.of(context).pop();
                      }),
                ]);
          });
    } else {
      showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            title: new Text("Send the items?"),
            actions: <Widget>[
              new FlatButton(
                  child: new Text("Close"),
                  onPressed: () {
                    Navigator.of(context).pop();
                  }),
              new FlatButton(
                  child: new Text("Send"),

                  onPressed: () async {
                    Map<String, dynamic> newDados = Map(); 
                    newDados["usuario"] = _usuarioController.text.trimLeft();
                    newDados["placa"] = _placaController.text.trimLeft();
                    newDados["box"] = _boxController.text.trimLeft();
                    newDados["tipo_veiculo"] = dropdownValue1;
                    _dadosList.add(newDados);
                    print(_pecasList + _dadosList);

                    Map<String, String> headers = new Map<String, String>();
                    headers["Content-type"] = "application/json";
                    headers["Accept"] = "application/json";
                    //String str = '{"take":55, "skip":"0"}';
                    final resp = await http.post('http://' + ipServidor,
                        body: jsonEncode(_dadosList +
                            _pecasList), //+ jsonEncode(_pecasList),
                        headers: headers);

                    print(resp.statusCode);

                    _dadosList
                        .clear(); //Cleans the list
                    print(resp.body);
                    if (resp.statusCode == 200) {
                      if (resp.body == "ok") {
                        setState(() {
                          print(_pecasList);
                          _pecasList.clear();
                          _placaController.clear();
                          _boxController.clear();
                          dropdownValue1 = "Vehicle type";

                          Navigator.of(context).pop();
                        });
                      } else {
                        showDialog(
                            context: context,
                            builder: (BuildContext context) {
                              return AlertDialog(
                                  title: new Text(
                                      "Error"),
                                  actions: <Widget>[
                                    new FlatButton(
                                        child: new Text("Close"),
                                        onPressed: () {
                                          Navigator.of(context).pop();
                                          Navigator.of(context).pop();
                                        }),
                                  ]);
                            });
                      }
                    } else {
                      print("communication error");
                      Navigator.of(context).pop();
                      showDialog(
                          context: context,
                          builder: (BuildContext context) {
                            return AlertDialog(
                                title: new Text("communication error"),
                                actions: <Widget>[
                                  new FlatButton(
                                      child: new Text("Close"),
                                      onPressed: () {
                                        Navigator.of(context).pop();
                                      }),
                                ]);
                          });
                    }
                  })
            ],
          );
        },
      );
    }
  }```

我已经为 flutter 基础项目 创建了示例项目,它具有高度的可维护性和干净性,复制这里的代码是 link

https://github.com/SouravKumarPandit/flutter_base_project

如果你不想要整个项目 structure.you 可以使用这个 以获得干净和结构化的代码

https://pub.dev/packages/mvvm_flutter#-installing-tab-

but if the internet isnt working it will not return the error because it will be trying forever to send the post.

要解决这个问题,您要做的是为您的 http 调用添加超时。

int timeout = 10;
try {
  http.Response response = await http.post('http://' + ipServidor,
      headers: headers,
      body: jsonEncode(_dadosList + _pecasList), encoding: utf8).
      timeout(Duration(seconds: timeout));
  if (response.statusCode == 200) {
    // do something
  } else {
    // handle it
  }
} on TimeoutException catch (e) {
  print('Timeout Error: $e');
} on SocketException catch (e) {
  print('Socket Error: $e');
} on Error catch (e) {
  print('General Error: $e');
}

Any other tips to improve the code are welcome.

我建议制作一个单独的 dart 文件,其中包含用于将在您的应用中重复出现的代码的不同部分的方法。

1) 创建类似于 http_handler.dart 的东西,它将具有异步方法 httpPost 和 httpGet。示例:

httpGet(String url, int attempts, int timeout) async {
  var parsedJson;
  bool success = false;
  int attempt=0;
  while(!success && attempt<attempts) {
    attempt++;
    // your httpGet try catch block
    // inside of it -> if response == 200 then success = true
    // also parse your json here
    if(!success) {
      sleep(const Duration(milliseconds: 500)); //sleep a bit between attempts
    }
  } 
  return parsedJson;
}

2) 创建类似于 confirm_dialog.dart

的内容
import 'package:flutter/material.dart';

enum ConfirmAction { CANCEL, ACCEPT }

    Future<ConfirmAction> ConfirmDialog(BuildContext context, String title, String content) async {
      return showDialog<ConfirmAction>(
        context: context,
        barrierDismissible: false, // user must tap on a button to close the dialog!
        builder: (BuildContext context) {
          return AlertDialog(
            title: Text(title),
            content: Text(content),
            actions: <Widget>[
              FlatButton(
                child: Text("NO"),
                onPressed: () {
                  Navigator.of(context).pop(ConfirmAction.CANCEL);
                },
              ),
              FlatButton(
                child: Text("YES"),
                onPressed: () {
                  Navigator.of(context).pop(ConfirmAction.ACCEPT);
                },
              )
            ],
          );
        },
      );
    }

然后当您需要用户确认或取消操作时,您可以像这样使用它:

  ConfirmAction action = await ConfirmDialog(context, "Dialog Title", "Dialog Content");
  if (action == ConfirmAction.ACCEPT) {
     //do something
  }