'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;
},
);
}
}
Solution 1:[1]
- Dio can't parse
FormData
instance if it is wrapped by another object or if you use nestedFormData
, so instead of doing this:
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,
};
do this:
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"
},
});
or something like that but but you must not wrapped FormData
with another object. Refer to this issue
- Assuming that:
- You are new in flutter.
- You have only two dart files.
- Only one class has external dependacies.
If the affirmations above are right, it is not necessary to use Provider, you can pass friendsList
and the current index to the FriendTextFields
: FriendTextFields(i, friendsList)
. And in the second file:
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();
}
and
@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;
},
);
}
Solution 2:[2]
The problem lies here:
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;
},
);
}
Here, you haven't assigned any value to the _AutoCompleteDemoState
variable. So, it is null. I don't know where it is coming from exactly. But it needs to be assigned some value.
Also, as I understand you're trying to access a variable inside another Widget. This can be done by passing the data to the next Widget as follows: What you were doing is passing the wrong data. Instead of passing the index, I would suggest that you pass this.
class FriendTextFields extends StatefulWidget {
final String friend;
FriendTextFields(this.friend);
final GlobalKey<_FriendTextFieldsState> serviceKey = new GlobalKey();
@override
_FriendTextFieldsState createState() => _FriendTextFieldsState();
}
However, I would very much recommend that you use a Provider for accessing such things. It will help you a lot. Check the Provider documentation over here. You can learn more about Provider over here.
Solution 3:[3]
There was the same error because the Logging Interceptor, which tried to json.encode my FormData.
working code just:
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);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 | Arsen Tatraev |