问题
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:
multi_image_picker: ^4.6.1
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,),),
),
),
),
),
],
),
);
}
}
回答1:
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.
回答2:
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
.
回答3:
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
回答4:
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);
回答5:
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();
}
}
回答6:
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);
来源:https://stackoverflow.com/questions/59780379/how-to-upload-multiple-images-using-dio-and-multi-image-picker-plugin-in-flutter