简体   繁体   中英

How to upload multiple images using Dio and multi_image_picker plugin in Flutter

I want to upload multiple-images using Dio and multi_image_picker plug-in in Flutter.

List<Asset> this is the problem because I can't convert from List<Asset> to List<File> so if you have any solutions help me.

try to use:

  1. multi_image_picker: ^4.6.1

  2. dio: ^3.0.4

Thanks

Bona SR.

import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:merchantside/helper/colorhelper.dart';
import 'package:merchantside/merchantside/login.dart';
import 'dart:async';
import 'package:multi_image_picker/multi_image_picker.dart';

class ListImages extends StatefulWidget {
  String errorMessage = "";
  @override
  _ListImagesState createState() => new _ListImagesState();
}

class _ListImagesState extends State<ListImages> {
  List<Asset> images = List<Asset>();
  List<File> listImages = [];
  @override
  void initState() {
    super.initState();
  }

  Widget buildGridView() {
    return GridView.count(
      crossAxisCount: 3,
      children: List.generate(images.length, (index) {
        Asset asset = images[index];
        return AssetThumb(
          asset: asset,
          width: 300,
          height: 300,
        );
      }),
    );
  }


  void _uploadFiles() async {
    String uid = await FlutterSecureStorage().read(key: "getTocken");
    try {
      var dio = Dio();
      FormData formData = new FormData.fromMap({
        "pictures[]": images, 
      });
      Response resp = await dio.post(
        mainUrl + 'merchant/upload-galleries',
        data: formData,
        onSendProgress: (int sent, int total) {
          //
        }, 
        options: Options(
          headers: {
            HttpHeaders.authorizationHeader: uid,
          },
        )
      );
      if(resp.statusCode == 200) {
        print("============= Print Resp data: ");
        print(resp.data);
      }

    } catch (e) {
      print(e);
    }
  }

  Future<void> loadAssets() async {
    List<Asset> resultList = List<Asset>();
    try {
      resultList = await MultiImagePicker.pickImages(
        maxImages: 6,
        enableCamera: true,
        selectedAssets: images,
        cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"),
        materialOptions: MaterialOptions(
          actionBarColor: "#abcdef",
          actionBarTitle: "Example App",
          allViewTitle: "All Photos",
          useDetailsView: false,
          selectCircleStrokeColor: "#000000",
        ),
      );
    } on Exception catch (e) {
      print(e);
    }

    // If the widget was removed from the tree while the asynchronous platform
    // message was in flight, we want to discard the reply rather than calling
    // setState to update our non-existent appearance.
    if (!mounted) return;
    setState(() {
      images = resultList;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        heroTag: "btn1",
        backgroundColor: ColorHelper.orange,
        child: Icon(Icons.add_photo_alternate),
        onPressed: loadAssets,
      ),
      appBar: new AppBar(
        title: Text('បញ្ជីរូបភាព'),
        backgroundColor: ColorHelper.orange,
      ),
      body: Column(
        children: <Widget>[
          //Error message
          errorMessage != "" ? 
          Container(
            margin: EdgeInsets.only(left: 10, right: 10, top: 10),
            height: 50,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.all(Radius.circular(4)),
              color: ColorHelper.red.withOpacity(0.5),
            ),
            child: Center(
              child: Text("$errorMessage", style: TextStyle(color: ColorHelper.swhite, fontSize: 15),),
            ),
          ):
          Container(),

          Expanded(
            child: Container(
              margin: EdgeInsets.only(left: 10, right: 10, top: 10),
              child: buildGridView(),
            ),
          ),
          SafeArea(
            child: Container(
              margin: EdgeInsets.all(10),
              decoration: BoxDecoration(
                color: ColorHelper.green,
                borderRadius: BorderRadius.all(Radius.circular(4))
              ),
              height: 50,
              child: InkWell(
                onTap: () {
                  if(images.length > 0) {
                    setState(() {
                      errorMessage = "";
                    });
                    // Call function upload multiple files
                    _uploadFiles();
                  } else {
                    setState(() {
                      errorMessage = "សូមបញ្ជូលរូបភាព";
                    });
                  } 
                },
                child: Center(
                  child: Text("រួចរាល់", style: TextStyle(color: ColorHelper.swhite, fontSize: 15, fontWeight: FontWeight.w500,),),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

when you pick images from gallery, called getFileList() and then called set state,first use global variable of list of file and clear each time this list when you again pick images.

  List<File> listFile = List<File>();
  images = resultList;
  _error = error;
   getFileList();

 void getFileList() async{
  listFile.clear();
 for(int i=0; i<images.length; i++){
  var path= await images[i].filePath;
  print(path);
  var file=await getImageFileFromAssets(path);
  print(file);
  listFile.add(file);
}
 setState(() {

 });
}

getImageFileFromAsset is used for conver asset to file

Future<File> getImageFileFromAsset(String path) async {
final file = File(path);
return file;

}

and use listFile in formdata.

Here's how to get a list of byte arrays from a list of Asset s:

List<Asset> images;
...

List<ByteData> byteDataList = await Future.wait(images.map((Asset image) => image.getByteData()));

List<Uint8List> byteArrayList = byteDataList.map((ByteData byteData) {
  ByteBuffer byteBuffer = byteData.buffer;
  return byteBuffer.asUint8List(byteData.offsetInBytes, byteBuffer.lengthInBytes);
}).toList();

Now you can use the list of byte arrays to build a payload using your network client of choice. For those not using 3rd party networking clients, that would be a MultipartRequest with multiple MultipartFile.fromBytes .

You don't need to convert Asset into File , You can send is as a byte array.

Only need to create the Multipart object of each image.

You can get the byte array from the Assets

 ByteData byteData = await asset.getByteData();
  List<int> imageData = byteData.buffer.asUint8List();

then it can pass through MultipartFile.fromBytes() method.

so it will look like,

  String url = "upload/url";

          List<Asset> images = List<Asset>();
          List<MultipartFile> multipartImageList = new List<MultipartFile>();
          if (null != images) {
            for (Asset asset in images) {
              ByteData byteData = await asset.getByteData();
              List<int> imageData = byteData.buffer.asUint8List();
              MultipartFile multipartFile = new MultipartFile.fromBytes(
                imageData,
                filename: 'load_image',
                contentType: MediaType("image", "jpg"),
              );
              multipartImageList.add(multipartFile);
            }

            FormData formData = FormData.fromMap({
              "multipartFiles": multipartImageList,
              "userId": '1'
            });

            Dio dio = new Dio();
            var response = await dio.post(url, data: formData);
          }

FYI

You can use file_picker and get list of files selected directly. It supports multi select and provides file path in response. It will be easiest way.

List<File> files = await FilePicker.getMultiFilePath(
          type: FileType.IMAGE);

I have used dio and multi_image plugin in my app and its working properly. What am doing is giving my code snippets here. You can say this is working version and should work in any app.

bloc class

final imageController = BehaviorSubject<List<Asset>>();
StreamSink<List<Asset>> get sinkImages =>
  imageController.sink;
Stream<List<Asset>> get getImages => imageController.stream;

Future<void> loadImages(imageCount) async {
List<Asset> imageList = List<Asset>();
String error = 'No Error Dectected';

try {
  imageList = await MultiImagePicker.pickImages(
    maxImages: imageCount,
    enableCamera: true,
    cupertinoOptions: CupertinoOptions(
      takePhotoIcon: "chat",
    ),
    materialOptions: MaterialOptions(
      actionBarColor: "#0A73B1",
      statusBarColor: "#0A73B1",
      actionBarTitle: "Select Image",
      allViewTitle: "All Photos",
      useDetailsView: false,
      selectCircleStrokeColor: "#000000",
    ),
  );
} on Exception catch (e) {
  error = e.toString();
  print(error);
}

_error = error;
imageController.add(imageList);
}

//call this method when you initiating api call

Future<GenericResponse> uploadImageRequest() async {
      RequestModel reqModel = RequestModel(
                     uploadImageList: getImages);

      final SharedPref prefs = SharedPref();
      String token = await prefs.readString(accessToken);

      GenericResponse response = await _application.repository
          .uploadRequest(reqModel: reqModel, accessToken: token);

      return response;
    }

So you already got your image list by this. And also set these list into your request model class. Now lets send these image as multipart using dio.

API class method

//call from repository class

Future<GenericResponse> uploadRequest(
  {RequestModel reqModel, String accessToken}) async {
return await _apiProvider.uploadRequest(
    reqModel: reqModel, accessToken: accessToken);
}

//upload image api request

Future<ResponseModel> uploadRequest(
  {RequestModel requestModel, String accessToken}) async {

List<MultipartFile> imageList = [];

imageList = await getMultiPartImages(requestModel.imageList);

FormData formData = FormData.fromMap(RequestModel(
        uploadImageList: imageList,
    .toJson());

try {
  Response response = await getDio().post(
    'api/endpoint',
    options: Options(headers: {
      'Authorization': 'Bearer $accessToken',
    }),
    data: formData,
  );
  return ResponseModel.fromJson(response.data);
} catch (error, stacktrace) {
  debugPrint("Exception occured: $error stackTrace: $stacktrace");
  return ResponseModel.withError(handleError(error));
 }
}

// podo model class

class RequestModel {
 var uploadImageList;

 RequestModel(
  {this.uploadImageList});

 RequestModel.fromJson(Map<String, dynamic> json) {
  uploadImageList = json['image_list'];
 }

Map<String, dynamic> toJson() {
 final Map<String, dynamic> data = new Map<String, dynamic>();
 data['image_list'] = this.uploadImageList;
 return data;
}

@override
String toString() {
  return toJson().toString();
 }
}

Simple and effective:

Map<String, dynamic> params = Map();
params['images'] = null;
Map<String, dynamic> headers = {
  HttpHeaders.contentTypeHeader: 'multipart/form-data',
};
List<MultipartFile> multipart = List<MultipartFile>();

//listImage is your list assets.
for (int i = 0; i < listImage.length; i++) {
  ByteData byteData = await listImage[i].getByteData();
  List<int> imageData = byteData.buffer.asUint8List();
  print("name: ${listImage[i].name}");
  String fileName = "${listImage[i].name}";
  multipart.add(MultipartFile.fromBytes(imageData, filename: fileName, contentType: MediaType("image", "jpg"),));
}
if (multipart.isNotEmpty){
  params['images'] = multipart;
}

FormData formData = new FormData.fromMap(params);
   FormData formData = FormData.fromMap({
      'id': 'ZE8980',
      'name': 'myTitle',
      'age':'22',
      'order_images': [
        for (var file in images)

         // ....SPRED images

        ...{
          await MultipartFile.fromFile(getImage(file).imageFile.path,
              filename: getImage(file).imageFile.path.split('/').last)
        }.toList()
      ]
    });
    Dio dio = new Dio();
    var response = await dio.post(url, data: formData);

Simple try this way,

String url1 =
    "Enter Your Url Here";

FormData data = FormData.fromMap({
  "equipment_id": equipmentid,
  "equipcount": equipcount,
  'equipImage': equipmentimages.map((item) => MultipartFile.fromFileSync(item.path,
          filename: item.path.split('/').last))
      .toList(),
  "equipNotes": equipmentnotes,
  "disposable_id": disposableid,
  "disposCount": disposablecount,
  "disposImage": disposableimages?.map((item) => MultipartFile.fromFileSync(item.path,
          filename: item.path.split('/').last))
      .toList(),
  "disposNotes": disposablenotes,
  "image": jobimage.map((item) => MultipartFile.fromFileSync(item.path,
          filename: item.path.split('/').last))
      .toList(),
  "note": jobnotes,
});

try {
  final response = await dio.put(url1, data: data);
  print(response.toString());
  return response.data["message"];
} on DioError catch (e) {
  print(e);
  throw e.response!.data['message'];
} catch (e) {
  print(e);
  throw e.toString();
}

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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