【问题标题】:DioError [DioErrorType.DEFAULT]: Converting object to an encodable object failed: Instance of 'FormData'DioError [DioErrorType.DEFAULT]:将对象转换为可编码对象失败:“FormData”实例
【发布时间】:2021-05-19 14:58:21
【问题描述】:

我是 Flutter 的新手。当我尝试将数据上传到服务器时,我遇到了一些问题,例如: 1.NoSuchMethodError:getter 'friendsList' 在 null 上被调用 2.DioError [DioErrorType.DEFAULT]:将对象转换为可编码对象失败:'FormData'的实例

import 'dart:convert';
import 'dart:io';

import 'package:data_collection/helperClass/testForAddButton.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:http_parser/http_parser.dart';

class AutoCompleteDemo extends StatefulWidget {
  @override
  _AutoCompleteDemoState createState() => _AutoCompleteDemoState();
}

class _AutoCompleteDemoState extends State<AutoCompleteDemo> {
  final hospitalNameEng = TextEditingController();
  final _serviceKey = GlobalKey<FormState>();
  static List<String> friendsList = [];
  File imageFile;
  String servicejson;
  bool loading = true;

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

  //for camera dialogBox
  Future<void> _showChoiceDialog(BuildContext context) {
    return showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            title: Text("Make a Choice"),
            content: SingleChildScrollView(
              child: ListBody(
                children: <Widget>[
                  GestureDetector(
                    child: Text("Gallery"),
                    onTap: () {
                      _openGallery(context);
                    },
                  ),
                  Padding(padding: EdgeInsets.all(5.0)),
                  GestureDetector(
                    child: Text("Camera"),
                    onTap: () {
                      _openCamera(context);
                    },
                  )
                ],
              ),
            ),
          );
        });
  }

//for image
  Widget _decideImageView() {
    if (imageFile == null) {
      return Text("No Image Selected");
    } else {
      Image.file(
        imageFile,
        width: 400,
        height: 400,
      );
    }
    return Image.file(
      imageFile,
      width: 400,
      height: 400,
    );
  }

//Dio part
  Dio dio = new Dio();
  Future postData() async {
    final String apiUrl = "MY_API";
    setState(() {
      servicejson = jsonEncode(friendsList);
    });

    String imageFileName = imageFile.path.split('/').last;
    FormData formData = new FormData.fromMap({
      "image": await MultipartFile.fromFile(imageFile.path,
          filename: imageFileName, contentType: new MediaType('image', 'png')),
      "type": "image/png"
    });

    dynamic allOfTheUploadData = {
      "name": hospitalNameEng,
      "Services": servicejson,
      "Image": formData,
    };
    var response = await dio.post(apiUrl,
        data: allOfTheUploadData,
        options: Options(headers: {
          "accept": "*/*",
          "Authorization": "Bearer accresstoken",
          "Content-type": "multipart/form-data",
        }));

    return response.data;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SingleChildScrollView(
        child: Column(
          children: <Widget>[
            Container(
              //margin: const EdgeInsets.only(bottom:5.0),
              child: TextField(
                controller: hospitalNameEng,
                decoration:
                    InputDecoration(hintText: 'Hospital Name In English'),
              ),
              padding: EdgeInsets.all(10.0),
            ),
            //service
            Container(
              child: Form(
                key: _serviceKey,
                child: Padding(
                  padding: const EdgeInsets.all(5.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        'Services',
                        style: TextStyle(
                            fontWeight: FontWeight.w700, fontSize: 16),
                      ),
                      ..._getServices(),
                      SizedBox(
                        height: 20,
                      ),
                    ],
                  ),
                ),
              ),
            ),
            //camera
            Container(
              child: Center(
                child: Column(
                  children: <Widget>[
                    RaisedButton(
                      onPressed: () {
                        _showChoiceDialog(context);
                      },
                      child: Text("Select Image"),
                    ),
                    _decideImageView(),
                  ],
                ),
              ),
            ),
            //send to server
            Container(
              child: Center(
                child: Column(
                  children: <Widget>[
                    FlatButton(
                      shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(18.0),
                          side: BorderSide(color: Colors.green)),
                      onPressed: () async {
                        try {
                          await postData().then((value) {
                            print(value);
                          });
                        } catch (e) {
                          print(e);
                        }
                      },
                      child: Text("Submit"),
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  //services
  List<Widget> _getServices() {
    List<Widget> friendsTextFieldsList = [];
    for (int i = 0; i < friendsList.length; i++) {
      friendsTextFieldsList.add(Padding(
        padding: const EdgeInsets.symmetric(vertical: 16.0),
        child: Row(
          children: [
            Expanded(child: FriendTextFields(i)),
            SizedBox(
              width: 16,
            ),
            // we need add button at last friends row only
            _addRemoveButton(i == friendsList.length - 1, i),
          ],
        ),
      ));
    }
    return friendsTextFieldsList;
  }

  Widget _addRemoveButton(bool add, int index) {
    return InkWell(
      onTap: () {
        if (add) {
          // add new text-fields at the top of all friends textfields
          friendsList.insert(0, null);
        } else
          friendsList.removeAt(index);
        setState(() {});
      },
      child: Container(
        width: 30,
        height: 30,
        decoration: BoxDecoration(
          color: (add) ? Colors.green : Colors.red,
          borderRadius: BorderRadius.circular(20),
        ),
        child: Icon(
          (add) ? Icons.add : Icons.remove,
          color: Colors.white,
        ),
      ),
    );
  }

  //gallery
  _openGallery(BuildContext context) async {
    var picture = await ImagePicker.pickImage(source: ImageSource.gallery);
    setState(() {
      imageFile = picture;
    });
    Navigator.of(context).pop();
  }

  //Camera
  _openCamera(BuildContext context) async {
    var picture = await ImagePicker.pickImage(source: ImageSource.camera);
    setState(() {
      imageFile = picture;
    });
    Navigator.of(context).pop();
  }
}

对于我在 Widget _getservices() 类中使用的添加按钮

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

import '../players.dart';

class FriendTextFields extends StatefulWidget {
  final int index;
  FriendTextFields(this.index);
  final GlobalKey<_FriendTextFieldsState> serviceKey = new GlobalKey();
  @override
  _FriendTextFieldsState createState() => _FriendTextFieldsState();
}

class _FriendTextFieldsState extends State<FriendTextFields> {
  GlobalKey<AutoCompleteTextFieldState<Division>> key = new GlobalKey();
  TextEditingController _serviceController;
  AutoCompleteTextField searchTextField;

  void _loadData() async {
    await PlayersViewModel.loadPlayers();
  }

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

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

  @override
  Widget build(BuildContext context) {
    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      // ignore: non_constant_identifier_names
      var _AutoCompleteDemoState;
      _serviceController.text = _AutoCompleteDemoState.friendsList[widget.index] ?? '';
    });
    var _AutoCompleteDemoState;
  
    return TextFormField(
      controller:
          _serviceController, // save text field data in friends list at index
      // whenever text field value changes

      onChanged: (v) => _AutoCompleteDemoState.friendsList[widget.index] = v,
      decoration: InputDecoration(hintText: 'Add a unique code: Service Name\''),
      validator: (v) {
        if (v.trim().isEmpty) return 'Please enter something';
        return null;
      },
    );
  }
}

【问题讨论】:

    标签: flutter dio


    【解决方案1】:
    • 如果 FormData 实例被另一个对象包裹或者如果您使用嵌套的 FormData,Dio 将无法解析它,所以不要这样做:
    FormData formData = new FormData.fromMap({
      "image": await MultipartFile.fromFile(imageFile.path,
          filename: imageFileName, contentType: new MediaType('image', 'png')),
      "type": "image/png"
    });
    
    dynamic allOfTheUploadData = {
      "name": hospitalNameEng,
      "Services": servicejson,
      "Image": formData,
    };
    

    这样做:

    FormData formData = new FormData.fromMap({
      "name": hospitalNameEng,
      "Services": servicejson,
      "Image": {
          "image": await MultipartFile.fromFile(imageFile.path,
              filename: imageFileName, contentType: new MediaType('image', 'png')),
          "type": "image/png"
      },
    });
    

    或类似的东西,但你不能用另一个对象包裹FormData。参考这个issue

    • 假设:
      1. 你是 Flutter 的新手。
      2. 您只有两个 dart 文件。
      3. 只有一个类具有外部依赖项。

    如果上面的肯定是对的,就不用使用Provider了,可以把friendsList和当前索引传给FriendTextFieldsFriendTextFields(i, friendsList)。在第二个文件中:

    class FriendTextFields extends StatefulWidget {
      final int index;
      final List<String> friendsList;
      FriendTextFields(this.index, this.friendsList);
      final GlobalKey<_FriendTextFieldsState> serviceKey = new GlobalKey();
      @override
      _FriendTextFieldsState createState() => _FriendTextFieldsState();
    }
    

      @override
      Widget build(BuildContext context) {
        WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
    
          _serviceController.text = widget.friendsList[widget.index] ?? '';
        });
        return TextFormField(
          controller:
              _serviceController, // save text field data in friends list at index
          // whenever text field value changes
    
          onChanged: (v) => widget.friendsList[widget.index] = v,
          decoration: InputDecoration(hintText: 'Add a unique code: Service Name\''),
          validator: (v) {
            if (v.trim().isEmpty) return 'Please enter something';
            return null;
          },
        );
      }
    

    【讨论】:

    • 谢谢您,先生,您能告诉我这个变量是如何初始化的吗?
    • 初始化变量意味着第一次为该变量赋值。我不能告诉你如何初始化你的变量,因为我不知道你想给它分配哪个值。但例如,如果您有一个名为 _HospitalState 的课程,您必须这样做 var hn = _HospitalState();
    • 并且不要忘记,以下划线“_”开头的类或对象名称是私有的,不能在声明它的文件之外使用。
    • 如果像你说的那样做,那么它不起作用。我尝试在初始化中添加 _HospitalState 但它不起作用。 :(
    • 对不起先生,这是我的错误,现在我编辑我的问题。请现在检查它不是 _HospitalState 它是来自我的 main.dart 文件的 _AutoCompleteDemoState
    【解决方案2】:

    问题出在这里:

    Widget build(BuildContext context) {
        WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
          // Here:
          var _AutoCompleteDemoState;
          _serviceController.text = _AutoCompleteDemoState.friendsList[widget.index] ?? '';
        });
        var _AutoCompleteDemoState;
      
        return TextFormField(
          controller:
              _serviceController, // save text field data in friends list at index
          // whenever text field value changes
    
          onChanged: (v) => _AutoCompleteDemoState.friendsList[widget.index] = v,
          decoration: InputDecoration(hintText: 'Add a unique code: Service Name\''),
          validator: (v) {
            if (v.trim().isEmpty) return 'Please enter something';
            return null;
          },
        );
      }
    

    在这里,您没有为_AutoCompleteDemoState 变量分配任何值。所以,它是空的。我不知道它究竟是从哪里来的。但它需要被赋予一些价值。

    另外,据我了解,您正在尝试访问另一个小部件中的变量。这可以通过将数据传递给下一个 Widget 来完成,如下所示: 您正在做的是传递错误的数据。我建议您不要传递索引,而是传递这个。

    class FriendTextFields extends StatefulWidget {
      final String friend;
      FriendTextFields(this.friend);
      final GlobalKey<_FriendTextFieldsState> serviceKey = new GlobalKey();
      @override
      _FriendTextFieldsState createState() => _FriendTextFieldsState();
    }
    

    但是,我强烈建议您使用 Provider 来访问此类内容。这会对你有很大帮助。检查here 上的提供者文档。您可以通过here了解更多关于Provider的信息。

    【讨论】:

    • 先生,我使用索引,当我单击添加按钮时,它会创建新的文本字段。如果我使用朋友,那么我在主文件中传递的内容。 List&lt;Widget&gt; _getServices() { List&lt;Widget&gt; friendsTextFieldsList = []; for (int i = 0; i &lt; friendsList.length; i++) { friendsTextFieldsList.add(Padding( padding: const EdgeInsets.symmetric(vertical: 16.0), child: Row( children: [ Expanded(child: FriendTextFields(i)), SizedBox(width: 16,), _addRemoveButton(i == friendsList.length - 1, i),],),)); } return friendsTextFieldsList; }
    • 你不能评论代码并期望我理解它。无论如何,正如我所说,如果你想做任何你想做的事情,你需要访问多个小部件中的friendsList 变量。这可以使用提供者来完成。请参考链接中的示例。
    • 我希望您没有发现该评论具有攻击性。我的观点是,为了让我理解您的观点,您需要将代码放在问题本身中以提供正确的格式。还有一点是,如果不使用 Providers 或任何其他状态管理工具,你会发现很难实现你所需要的。所以,也请看看。
    • 我的代码就是我在问题中给出的全部内容。在那里我使用了 2 个 dart 类,是的,现在我尝试由提供者来执行此操作。如果使用提供商遇到任何问题,我会敲你。
    • 太棒了!!!当然,如果您遇到任何问题,请让社区知道,他们会随时提供帮助。
    猜你喜欢
    • 2021-08-09
    • 2020-07-18
    • 2021-11-04
    • 2020-08-21
    • 2023-04-09
    • 1970-01-01
    • 2020-12-31
    • 2018-09-20
    • 2021-10-05
    相关资源
    最近更新 更多