繁体   English   中英

DioError [DioErrorType.DEFAULT]:将 object 转换为可编码的 object 失败:“FormData”实例

[英]DioError [DioErrorType.DEFAULT]: Converting object to an encodable object failed: Instance of 'FormData'

我是 Flutter 的新手。当我尝试将数据上传到服务器时,我遇到了一些问题,例如: 1.NoSuchMethodError:在 null 上调用了 getter 'friendsList' 2.DioError [DioErrorType.DEFAULT]:将 object 转换为可编码的 object失败:“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() 中使用的添加按钮 class

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;
      },
    );
  }
}

  • 如果 FormData 实例被另一个 object 包装,或者如果您使用嵌套FormData ,则 Dio 无法解析FormData实例,因此不要这样做:
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"
  },
});

或类似的东西,但你不能用另一个 object 包装FormData 参考这个问题

  • 假如说:
    1. 你是 flutter 的新手。
    2. 您只有两个 dart 文件。
    3. 只有一个 class 具有外部依赖性。

如果上面的肯定是对的,就不需要使用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;
      },
    );
  }

问题出在这里:

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变量分配任何值。 所以,它是 null。 我不知道它究竟是从哪里来的。 但它需要被赋予一些价值。

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

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

但是,我非常建议您使用 Provider 来访问这些东西。 这会对你有很大帮助。 此处查看 Provider 文档。 您可以在此处了解有关 Provider 的更多信息。

由于日志记录拦截器出现了同样的错误,它试图对我的 FormData 进行 json.encode。

工作代码只是:

var file = File(path);
var fileName = file.path.split('/').last;
FormData formData = FormData.fromMap({
  "file": await MultipartFile.fromFile(file.path, filename: fileName),
});

Response resp = await dio.post(endpoint, data: formData);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM