Retrofit Uploading multiple images to a single key
We can use MultipartBody.Part
array to upload an array of images to a single key.
Here is the solution
WebServicesAPI
@Multipart
@POST(WebServices.UPLOAD_SURVEY)
Call<UploadSurveyResponseModel> uploadSurvey(@Part MultipartBody.Part[] surveyImage,
@Part MultipartBody.Part propertyImage,
@Part("DRA") RequestBody dra);
Here is the method for uploading the files.
private void requestUploadSurvey () {
File propertyImageFile = new File(surveyModel.getPropertyImagePath());
RequestBody propertyImage = RequestBody.create(MediaType.parse("image/*"),
propertyImageFile);
MultipartBody.Part propertyImagePart = MultipartBody.Part.createFormData("PropertyImage",
propertyImageFile.getName(),
propertyImage);
MultipartBody.Part[] surveyImagesParts = new MultipartBody.Part[surveyModel.getPicturesList()
.size()];
for (int index = 0; index <
surveyModel.getPicturesList()
.size(); index++) {
Log.d(TAG,
"requestUploadSurvey: survey image " +
index +
" " +
surveyModel.getPicturesList()
.get(index)
.getImagePath());
File file = new File(surveyModel.getPicturesList()
.get(index)
.getImagePath());
RequestBody surveyBody = RequestBody.create(MediaType.parse("image/*"),
file);
surveyImagesParts[index] = MultipartBody.Part.createFormData("SurveyImage",
file.getName(),
surveyBody);
}
final WebServicesAPI webServicesAPI = RetrofitManager.getInstance()
.getRetrofit()
.create(WebServicesAPI.class);
Call<UploadSurveyResponseModel> surveyResponse = null;
if (surveyImagesParts != null) {
surveyResponse = webServicesAPI.uploadSurvey(surveyImagesParts,
propertyImagePart,
draBody);
}
surveyResponse.enqueue(this);
}
How To Upload Multiple Image to single key using retrofit in android
my key is multipleimage[] like this and it is working well in this
VolleyMultipartRequest volleyMultipartRequest = new
VolleyMultipartRequest(com.android.volley.Request.Method.POST, url,
new com.android.volley.Response.Listener<NetworkResponse>() {
@Override
public void onResponse(NetworkResponse response) {
try {
Log.e("respps", "onResponse: " + response);
Toast.makeText(PostFormActivity.this,"UploadSucessfully", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
Log.e("respps", "onResponse:Exp " + e.getMessage());
Toast.makeText(PostFormActivity.this, "Upload Fail", Toast.LENGTH_SHORT).show();
}
}
},
new com.android.volley.Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("ERROR", error.toString());
Log.e("respps", "onResponse:Err " + error);
Toast.makeText(PostFormActivity.this, "Upload Fail Try After Some Time", Toast.LENGTH_SHORT).show();
}
}) {
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("id", id);
params.put("id2", id2);
params.put("id3",id3);
params.put("id4", id4);
return params;
}
@Override
protected Map<String, DataPart> getByteData() {
Map<String, DataPart> params = new HashMap<>();
long imagename = System.currentTimeMillis();
params.put("banner", new DataPart(imagename + ".png", getFileDataFromDrawable(img)));
for (int i = 0; i < imagesEncodedList1.size(); i++) {
params.put("multipleimage" + "[" + i + "]", new DataPart(imagename + ".png", getFileDataFromDrawable(imagesEncodedList1.get(i))));
}
return params;
}
};
{
int socketTimeout = 60000;
RetryPolicy policy = new DefaultRetryPolicy(socketTimeout, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
volleyMultipartRequest.setRetryPolicy(policy);
RequestQueue requestQueue = Volley.newRequestQueue(PostFormActivity.this);
requestQueue.add(volleyMultipartRequest);
}
volley multipart request
public class VolleyMultipartRequest extends Request<NetworkResponse> {
private final String twoHyphens = "--";
private final String lineEnd = "\r\n";
private final String boundary = "apiclient-" + System.currentTimeMillis();
private Response.Listener<NetworkResponse> mListener;
private Response.ErrorListener mErrorListener;
private Map<String, String> mHeaders;
public VolleyMultipartRequest(int method, String url,
Response.Listener<NetworkResponse> listener,
Response.ErrorListener errorListener) {
super(method, url, errorListener);
this.mListener = listener;
this.mErrorListener = errorListener;
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
return (mHeaders != null) ? mHeaders : super.getHeaders();
}
@Override
public String getBodyContentType() {
return "multipart/form-data;boundary=" + boundary;
}
@Override
public byte[] getBody() throws AuthFailureError {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
try {
// populate text payload
Map<String, String> params = getParams();
if (params != null && params.size() > 0) {
textParse(dos, params, getParamsEncoding());
}
// populate data byte payload
Map<String, DataPart> data = getByteData();
if (data != null && data.size() > 0) {
dataParse(dos, data);
}
// close multipart form data after text and file data
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* Custom method handle data payload.
*
* @return Map data part label with data byte
* @throws AuthFailureError
*/
protected Map<String, DataPart> getByteData() throws AuthFailureError {
return null;
}
@Override
protected Response<NetworkResponse> parseNetworkResponse(NetworkResponse response) {
try {
return Response.success(
response,
HttpHeaderParser.parseCacheHeaders(response));
} catch (Exception e) {
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(NetworkResponse response) {
mListener.onResponse(response);
}
@Override
public void deliverError(VolleyError error) {
mErrorListener.onErrorResponse(error);
}
/**
* Parse string map into data output stream by key and value.
*
* @param dataOutputStream data output stream handle string parsing
* @param params string inputs collection
* @param encoding encode the inputs, default UTF-8
* @throws IOException
*/
private void textParse(DataOutputStream dataOutputStream, Map<String, String> params, String encoding) throws IOException {
try {
for (Map.Entry<String, String> entry : params.entrySet()) {
buildTextPart(dataOutputStream, entry.getKey(), entry.getValue());
}
} catch (UnsupportedEncodingException uee) {
throw new RuntimeException("Encoding not supported: " + encoding, uee);
}
}
/**
* Parse data into data output stream.
*
* @param dataOutputStream data output stream handle file attachment
* @param data loop through data
* @throws IOException
*/
private void dataParse(DataOutputStream dataOutputStream, Map<String, DataPart> data) throws IOException {
for (Map.Entry<String, DataPart> entry : data.entrySet()) {
buildDataPart(dataOutputStream, entry.getValue(), entry.getKey());
}
}
/**
* Write string data into header and data output stream.
*
* @param dataOutputStream data output stream handle string parsing
* @param parameterName name of input
* @param parameterValue value of input
* @throws IOException
*/
private void buildTextPart(DataOutputStream dataOutputStream, String parameterName, String parameterValue) throws IOException {
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + lineEnd);
dataOutputStream.writeBytes(lineEnd);
dataOutputStream.writeBytes(parameterValue + lineEnd);
}
/**
* Write data file into header and data output stream.
*
* @param dataOutputStream data output stream handle data parsing
* @param dataFile data byte as DataPart from collection
* @param inputName name of data input
* @throws IOException
*/
private void buildDataPart(DataOutputStream dataOutputStream, DataPart dataFile, String inputName) throws IOException {
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" +
inputName + "\"; filename=\"" + dataFile.getFileName() + "\"" + lineEnd);
if (dataFile.getType() != null && !dataFile.getType().trim().isEmpty()) {
dataOutputStream.writeBytes("Content-Type: " + dataFile.getType() + lineEnd);
}
dataOutputStream.writeBytes(lineEnd);
ByteArrayInputStream fileInputStream = new ByteArrayInputStream(dataFile.getContent());
int bytesAvailable = fileInputStream.available();
int maxBufferSize = 1024 * 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
byte[] buffer = new byte[bufferSize];
int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dataOutputStream.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
dataOutputStream.writeBytes(lineEnd);
}
public class DataPart {
private String fileName;
private byte[] content;
private String type;
public DataPart() {
}
DataPart(String name) {
fileName = name;
// content = data;
}
public DataPart(String s, byte[] fileDataFromDrawable) {
fileName = s;
content=fileDataFromDrawable;
}
String getFileName() {
return fileName;
}
byte[] getContent() {
return content;
}
String getType() {
return type;
}
}
}
get file data from drawable
public byte[] getFileDataFromDrawable(Bitmap bitmap) {
ByteArrayOutputStream byteArrayOutputStream = new
ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 80,
byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
}
and here my onActivityResult
if (requestCode == 44 && resultCode == RESULT_OK && data != null && data.getData() != null) {
String[] filePathColumn = { MediaStore.Images.Media.DATA };
imagesEncodedList = new ArrayList<String>();
imagesEncodedList1 = new ArrayList<Bitmap>();
if(data.getClipData() != null) {
int count = data.getClipData().getItemCount();
for(int i = 0; i < count; i++) {
Uri imageUri = data.getClipData().getItemAt(i).getUri();
Cursor cursor = getContentResolver().query(data.getClipData().getItemAt(i).getUri(), filePathColumn, null, null, null);
// Move to first row
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
imageEncoded = cursor.getString(columnIndex);
imagesEncodedList.add(imageEncoded);
try {
Bitmap bitmap = MediaStore
.Images
.Media
.getBitmap(PostFormActivity.this.getContentResolver(), data.getClipData().getItemAt(i).getUri());
imagesEncodedList1.add(bitmap);
Log.d("TAG", "onActivityResult:trybitmap "+bitmap);
}
catch (Exception e){
e.printStackTrace();
}
cursor.close();
//do what do you want to do
}
}
}
Select Multiple Image from gallery
private void selectMultipleImage() {
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
startActivityForResult(Intent.createChooser(intent, "Select
images"),44);
}
Sending multiple images using retrofit in a single key
file was not uploading because file was not Creating Properly
thanks to github i found a way to create a file Properly
GitHub link for creating file
Also Made a little bit of changes in my code according to this answer
link for stackoverflow answer
How to upload multiple images in android using retrofit
public interface UploadImages {
@Multipart
@POST("upload_images")
Call<ResponseBody> uploadMultipleFiles(
@Part("text") RequestBody text,
@Part List<MultipartBody.Part> images);
}
OR
@Multipart
@POST("upload_images")
Call<ResponseBody> uploadMultipleFiles(@Part("text") RequestBody text,
@Part MultipartBody.Part file1,
@Part MultipartBody.Part file2,
@Part MultipartBody.Part file3);
How to upload Multiple images in one Request using Retrofit 2 and php as a back end?
after searching and asking around, here is a full, tested and self-contained solution.
1.create the service interface.
public interface FileUploadService {
@Multipart
@POST("YOUR_URL/image_uploader.php")
Call<Response> uploadImages( @Part List<MultipartBody.Part> images);
}
and the Response.java
public class Response{
private String error;
private String message;
//getters and setters
}
2- uploadImages method
I pass a list of URI from onActivityResult()
method, then I get the actual file path with the help of FileUtiles "the link to the class is commented"
//code to upload
//the path is returned from the gallery
void uploadImages(List<Uri> paths) {
List<MultipartBody.Part> list = new ArrayList<>();
int i = 0;
for (Uri uri : paths) {
String fileName = FileUtils.getFile(this, uri).getName();
//very important files[]
MultipartBody.Part imageRequest = prepareFilePart("file[]", uri);
list.add(imageRequest);
}
Retrofit builder = new Retrofit.Builder().baseUrl(ROOT_URL).addConverterFactory(GsonConverterFactory.create()).build();
FileUploadService fileUploadService = builder.create(FileUploadService.class);
Call<Response> call = fileUploadService.uploadImages(list);
call.enqueue(new Callback<Response>() {
@Override
public void onResponse(Call<Response> call, Response<Response> response) {
Log.e("main", "the message is ----> " + response.body().getMessage());
Log.e("main", "the error is ----> " + response.body().getError());
}
@Override
public void onFailure(Call<Response> call, Throwable throwable) {
Log.e("main", "on error is called and the error is ----> " + throwable.getMessage());
}
});
}
and the helper method used above
@NonNull
private MultipartBody.Part prepareFilePart(String partName, Uri fileUri) {
// https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java
// use the FileUtils to get the actual file by uri
File file = FileUtils.getFile(this, fileUri);
//compress the image using Compressor lib
Timber.d("size of image before compression --> " + file.getTotalSpace());
compressedImageFile = new Compressor(this).compressToFile(file);
Timber.d("size of image after compression --> " + compressedImageFile.getTotalSpace());
// create RequestBody instance from file
RequestBody requestFile =
RequestBody.create(
MediaType.parse(getContentResolver().getType(fileUri)),
compressedImageFile);
// MultipartBody.Part is used to send also the actual file name
return MultipartBody.Part.createFormData(partName, file.getName(), requestFile);
}
3-My php code image_uploader.php:
<?php
$file_path = "upload/";
$full_path="http://bishoy.esy.es/retrofit/".$file_path;
$img = $_FILES['file'];
$response['message'] = "names : ";
if(!empty($img)){
for($i=0;$i<count($_FILES['file']['tmp_name']);$i++){
$response['error'] = false;
$response['message'] = "number of files recieved is = ".count($_FILES['file']['name']);
if(move_uploaded_file($_FILES['file']['tmp_name'][$i],"upload/".$_FILES['file']['name'][$i])){
$response['error'] = false;
$response['message'] = $response['message']. "moved sucessfully :: ";
}else{
$response['error'] = true;
$response['message'] = $response['message'] ."cant move :::" .$file_path ;
}
}
}
else{
$response['error'] = true;
$response['message'] = "no files recieved !";
}
echo json_encode($response);
?>
How to send multiple images to server using retrofit 2.3.0 in android?
Instead of using @Part try @Field
@Multipart
@POST("/api/mbrphotos/prfImgIU/{memberId}/{actionType}")
Call<JsonObject> postImage(@Part("memberId") RequestBody memberId,
@Part("actionType") RequestBody actionType,
@Part MultipartBody.Part[] multipartTypedOutput);
and in your Activity
use this method to send the post
public void sendPost(String memberId, String actionType) {
final ProgressDialog dialog = new ProgressDialog(this);
dialog.setMessage("Please wait...");
dialog.setCancelable(false);
dialog.show();
MultipartBody.Part[] multipartTypedOutput = new MultipartBody.Part[imageModelArrayList.size()];
for (int index = 0; index < imageModelArrayList.size(); index++) {
Log.d("Upload request", "requestUploadSurvey: survey image " + index + " " + imageModelArrayList.get(index).path);
File file2 = new File(imageModelArrayList.get(index).path);
RequestBody surveyBody = RequestBody.create(MediaType.parse("image/*"), file2);
multipartTypedOutput[index] = MultipartBody.Part.createFormData("imageFiles[]", file2.getPath(), surveyBody);
}
RequestBody memberId1 = RequestBody.create(MediaType.parse("text/plain"), memberId);
RequestBody actionType1 = RequestBody.create(MediaType.parse("text/plain"), actionType);
apiService.postImage(memberId1, actionType1, multipartTypedOutput).enqueue(new Callback<JsonObject>() {
@Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
Log.d("fb_regist_response", "--->" + "" + response);
dialog.dismiss();
}
@Override
public void onFailure(Call<JsonObject> call, Throwable t) {
Log.d("onFail_fb_regist_res", t.getMessage());
dialog.dismiss();
}
});
}
Related Topics
Android - Swipe to Delete Recyclerview
Broadcast Receiver Won't Receive Camera Event
How to Tell If a Closed Path Contains a Given Point
Cordova Plugin Development - Adding Aar
Importing Jar Libraries into Android-Studio
How to Write Jarlist Cache File While Creating Android Project
Run-As Package 'A.B.C' Is Unknown - Galaxy S4 Jellybean or Android 4.3
Android M Weird Shared Preferences Issue
How to Schedule Notifications Using Workmanager
Android Accelerometer Not Working When Screen Is Turned Off
How to Fix "Failed to Sync Vcpu Reg" Error
Android and Setting Alpha for (Image) View Alpha
Extended Surfaceview's Ondraw() Method Never Called
How to Create Expandable Listview in Flutter
How to Change the Android App Package Name When Assembling with Gradle