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: sitatech

  • Dio can't parse FormData instance if it is wrapped by another object or if you use nested FormData, 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:
    1. You are new in flutter.
    2. You have only two dart files.
    3. 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: Preet Shah

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: Arsen Tatraev

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