DioError [DioErrorType.DEFAULT]:将对象转换为可编码对象失败:'FormData' 的实例
DioError [DioErrorType.DEFAULT]: Converting object to an encodable object failed: Instance of 'FormData'
I'm new in Flutter. When i try to upload data to the server i faced some problems like:
1.NoSuchMethodError: The getter 'friendsList' was called on null
2.DioError [DioErrorType.DEFAULT]: Converting object to an encodable object failed: Instance of '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();
}
}
For add button which i used in 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;
},
);
}
}
- Dio 无法解析
FormData
实例,如果它被另一个对象包裹或者如果您使用嵌套 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"
},
});
或类似的东西,但你不能用另一个对象包裹 FormData
。参考这个issue
- 假设:
- 你是 flutter 的新手。
- 您只有两个飞镖文件。
- 只有一个 class 具有外部依赖性。
如果上面的判断是对的,就没有必要使用Provider了,可以将friendsList
和当前索引传给FriendTextFields
:FriendTextFields(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
变量赋值。所以,它是空的。我不知道它到底是从哪里来的。但是需要给它赋值。
此外,据我所知,您正在尝试访问另一个 Widget 中的变量。这可以通过将数据传递给下一个 Widget 来完成,如下所示:
您正在做的是传递错误的数据。与其传递索引,我建议你传递这个。
class FriendTextFields extends StatefulWidget {
final String friend;
FriendTextFields(this.friend);
final GlobalKey<_FriendTextFieldsState> serviceKey = new GlobalKey();
@override
_FriendTextFieldsState createState() => _FriendTextFieldsState();
}
但是,我强烈建议您使用 Provider 来访问此类内容。它会对你有很大帮助。通过 here. You can learn more about Provider over here.
查看提供程序文档
日志拦截器出现了同样的错误,它试图 json.encode 我的 FormData。
工作代码只是:
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);
I'm new in Flutter. When i try to upload data to the server i faced some problems like: 1.NoSuchMethodError: The getter 'friendsList' was called on null 2.DioError [DioErrorType.DEFAULT]: Converting object to an encodable object failed: Instance of '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();
}
}
For add button which i used in 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;
},
);
}
}
- Dio 无法解析
FormData
实例,如果它被另一个对象包裹或者如果您使用嵌套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"
},
});
或类似的东西,但你不能用另一个对象包裹 FormData
。参考这个issue
- 假设:
- 你是 flutter 的新手。
- 您只有两个飞镖文件。
- 只有一个 class 具有外部依赖性。
如果上面的判断是对的,就没有必要使用Provider了,可以将friendsList
和当前索引传给FriendTextFields
:FriendTextFields(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
变量赋值。所以,它是空的。我不知道它到底是从哪里来的。但是需要给它赋值。
此外,据我所知,您正在尝试访问另一个 Widget 中的变量。这可以通过将数据传递给下一个 Widget 来完成,如下所示: 您正在做的是传递错误的数据。与其传递索引,我建议你传递这个。
class FriendTextFields extends StatefulWidget {
final String friend;
FriendTextFields(this.friend);
final GlobalKey<_FriendTextFieldsState> serviceKey = new GlobalKey();
@override
_FriendTextFieldsState createState() => _FriendTextFieldsState();
}
但是,我强烈建议您使用 Provider 来访问此类内容。它会对你有很大帮助。通过 here. You can learn more about Provider over here.
查看提供程序文档日志拦截器出现了同样的错误,它试图 json.encode 我的 FormData。
工作代码只是:
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);