I'm trying to down/upload a file with retrofit 2 but can't find any tutorials examples on how to do so.
My code for downloading is:
#GET("documents/checkout")
public Call<File> checkout(#Query(value = "documentUrl") String documentUrl, #Query(value = "accessToken") String accessToken, #Query(value = "readOnly") boolean readOnly);
and
Call<File> call = RetrofitSingleton.getInstance(serverAddress)
.checkout(document.getContentUrl(), apiToken, readOnly[i]);
call.enqueue(new Callback<File>() {
#Override
public void onResponse(Response<File> response,
Retrofit retrofit) {
String fileName = document.getFileName();
try {
System.out.println(response.body());
long fileLength = response.body().length();
InputStream input = new FileInputStream(response.body());
File path = Environment.getExternalStorageDirectory();
File file = new File(path, fileName);
BufferedOutputStream output = new BufferedOutputStream(
new FileOutputStream(file));
byte data[] = new byte[1024];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
total += count;
output.write(data, 0, count);
}
output.flush();
output.close();
} catch (IOException e) {
String logTag = "TEMPTAG";
Log.e(logTag, "Error while writing file!");
Log.e(logTag, e.toString());
}
}
#Override
public void onFailure(Throwable t) {
// TODO: Error handling
System.out.println(t.toString());
}
});
I've tried with Call and Call but nothing seems to work.
The server-side code writes the file's bytes into HttpServletResponse's output stream after setting the headers and mime type correctly.
What am I doing wrong?
Finally, the upload code:
#Multipart
#POST("documents/checkin")
public Call<String> checkin(#Query(value = "documentId") String documentId, #Query(value = "name") String fileName, #Query(value = "accessToken") String accessToken, #Part("file") RequestBody file);
and
RequestBody requestBody = RequestBody.create(MediaType.parse(document.getMimeType()), file);
Call<String> call = RetrofitSingleton.getInstance(serverAddress).checkin(documentId, document.getFileName(), apiToken, requestBody);
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Response<String> response, Retrofit retrofit) {
System.out.println(response.body());
}
#Override
public void onFailure(Throwable t) {
System.out.println(t.toString());
}
});
Thanks!
Edit:
After the answer, downloading only yields a corrupted file (without the #Streaming), uploading doesn't as well. When I use the above code, the server returns a 400 error. After changing it to
RequestBody requestBody = RequestBody.create(MediaType.parse(document.getMimeType()), file);
MultipartBuilder multipartBuilder = new MultipartBuilder();
multipartBuilder.addFormDataPart("file", document.getFileName(), requestBody);
Call<String> call = RetrofitSingleton.getInstance(serverAddress).checkin(documentId, document.getFileName(), apiToken, multipartBuilder.build());
, the request executes but the backend doesn't seem to receive a file.
Backend code:
#RequestMapping(value = "/documents/checkin", method = RequestMethod.POST)
public void checkInDocument(#RequestParam String documentId,
#RequestParam String name, #RequestParam MultipartFile file,
#RequestParam String accessToken, HttpServletResponse response)
What am I doing wrong? I was able to use the backend from plain Java with the Apache HttpClient:
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addBinaryBody("file", new File("E:\\temp\\test.jpg"));
HttpEntity httpEntity = builder.build();
System.out.println("HttpEntity " + EntityUtils.toString(httpEntity.));
HttpPost httpPost = new HttpPost(uri);
httpPost.setEntity(httpEntity);
Edit v2
For anyone interested, both up- and downloading work now: These are the solutions:
Service:
#GET("documents/checkout")
public Call<ResponseBody> checkout(#Query(value = "documentUrl") String documentUrl, #Query(value = "accessToken") String accessToken, #Query(value = "readOnly") boolean readOnly);
#Multipart
#POST("documents/checkin")
public Call<String> checkin(#Query(value = "documentId") String documentId, #Query(value = "name") String fileName, #Query(value = "accessToken") String accessToken, #Part("file") RequestBody file);
Download Code:
Call<ResponseBody> call = RetrofitSingleton.getInstance(serverAddress)
.checkout(document.getContentUrl(), apiToken, readOnly[i]);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Response<ResponseBody> response,
Retrofit retrofit) {
String fileName = document.getFileName();
try {
File path = Environment.getExternalStorageDirectory();
File file = new File(path, fileName);
FileOutputStream fileOutputStream = new FileOutputStream(file);
IOUtils.write(response.body().bytes(), fileOutputStream);
} catch (IOException e) {
Log.e(logTag, "Error while writing file!");
Log.e(logTag, e.toString());
}
}
#Override
public void onFailure(Throwable t) {
// TODO: Error handling
System.out.println(t.toString());
}
});
Upload Code:
Call<String> call = RetrofitSingleton
.getInstance(serverAddress).checkin(documentId,
document.getFileName(), apiToken,
multipartBuilder.build());
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Response<String> response,
Retrofit retrofit) {
// Handle response here
}
#Override
public void onFailure(Throwable t) {
// TODO: Error handling
System.out.println("Error");
System.out.println(t.toString());
}
});
For downloading, you can use ResponseBody as your return type --
#GET("documents/checkout")
#Streaming
public Call<ResponseBody> checkout(#Query("documentUrl") String documentUrl, #Query("accessToken") String accessToken, #Query("readOnly") boolean readOnly);
and you can get the ResponseBody input stream in your call back --
Call<ResponseBody> call = RetrofitSingleton.getInstance(serverAddress)
.checkout(document.getContentUrl(), apiToken, readOnly[i]);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Response<ResponseBody> response,
Retrofit retrofit) {
String fileName = document.getFileName();
try {
InputStream input = response.body().byteStream();
// rest of your code
Your upload looks okay at first glance if you server handles multipart messages correctly. Is it working? If not, can you explain the failure mode? You also might be able to simplify by not making it multipart. Remove the #Multipart annotation and convert #Path to #Body --
#POST("documents/checkin")
public Call<String> checkin(#Query("documentId") String documentId, #Query("name") String fileName, #Query("accessToken") String accessToken, #Body RequestBody file);
I am using retrofit 2.0.0-beta2 and I had an issue uploading image by using multipart request. I solved it by using this answer: https://stackoverflow.com/a/32796626/2915075
The key for me was to use standard POST with MultipartRequestBody instead of #Multipart annotated request.
Here is my code:
Retrofit service class
#POST("photo")
Call<JsonElement> uploadPhoto(#Body RequestBody imageFile, #Query("sessionId"));
Usage from activity, fragment:
RequestBody fileBody = RequestBody.create(MediaType.parse("image/jpeg"), imageFile);
MultipartBuilder multipartBuilder = new MultipartBuilder();
multipartBuilder.addFormDataPart("photo", imageFile.getName(), fileBody);
RequestBody fileRequestBody = multipartBuilder.build();
//call
mRestClient.getRetrofitService().uploadProfilePhoto(fileRequestBody, sessionId);
i have the same problems, and i found a solution to upload files, that described here
Is it possible to show progress bar when upload image via Retrofit 2
Also I had this problem, This is how i try to solve my problem (RETROFIT 2 )
//1. What We Need From Server ( upload.php Script )
public class FromServer {
String result;
}
//2. Which Interface To Communicate Our upload.php Script?
public interface ServerAPI {
#Multipart
#POST("upload.php")//Our Destination PHP Script
Call<List<FromServer>> upload(
#Part("file_name") String file_name,
#Part("file") RequestBody description);
Retrofit retrofit =
new Retrofit.Builder()
.baseUrl("http://192.168.43.135/retro/") // REMEMBER TO END with /
.addConverterFactory(GsonConverterFactory.create())
.build();
}
//3. How To Upload
private void upload(){
ServerAPI api = ServerAPI.retrofit.create(ServerAPI.class);
File from_phone = FileUtils.getFile(Environment.getExternalStorageDirectory()+"/aa.jpg"); //org.apache.commons.io.FileUtils
RequestBody to_server = RequestBody.create(MediaType.parse("multipart/form-data"), from_phone);
api.upload(from_phone.getName(),to_server).enqueue(new Callback<List<FromServer>>() {
#Override
public void onResponse(Call<List<FromServer>> call, Response<List<FromServer>> response) {
Toast.makeText(MainActivity.this, response.body().get(0).result, Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<List<FromServer>> call, Throwable t) { }
});
}
//4. upload.php
<?php
$pic = $_POST['file_name'];
$pic = str_replace("\"", "", $pic); //REMOVE " from file name
if(file_exists($pic)){unlink($pic);}
$f = fopen($pic, "w");
fwrite($f,$_POST['file']);
fclose($f);
$arr[] = array("result"=>"Done");
print(json_encode($arr));
?>
You can refer tutorial for Image Download using Retrofit 2.0
For the time being you can refer following functions for image download:
void getRetrofitImage() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build();
RetrofitImageAPI service = retrofit.create(RetrofitImageAPI.class);
Call<ResponseBody> call = service.getImageDetails();
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Response<ResponseBody> response, Retrofit retrofit) {
try {
Log.d("onResponse", "Response came from server");
boolean FileDownloaded = DownloadImage(response.body());
Log.d("onResponse", "Image is downloaded and saved ? " + FileDownloaded);
} catch (Exception e) {
Log.d("onResponse", "There is an error");
e.printStackTrace();
}
}
#Override
public void onFailure(Throwable t) {
Log.d("onFailure", t.toString());
}
});
}
Following is the file handling part image download using Retrofit 2.0
private boolean DownloadImage(ResponseBody body) {
try {
Log.d("DownloadImage", "Reading and writing file");
InputStream in = null;
FileOutputStream out = null;
try {
in = body.byteStream();
out = new FileOutputStream(getExternalFilesDir(null) + File.separator + "AndroidTutorialPoint.jpg");
int c;
while ((c = in.read()) != -1) {
out.write(c);
}
}
catch (IOException e) {
Log.d("DownloadImage",e.toString());
return false;
}
finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
int width, height;
ImageView image = (ImageView) findViewById(R.id.imageViewId);
Bitmap bMap = BitmapFactory.decodeFile(getExternalFilesDir(null) + File.separator + "AndroidTutorialPoint.jpg");
width = 2*bMap.getWidth();
height = 6*bMap.getHeight();
Bitmap bMap2 = Bitmap.createScaledBitmap(bMap, width, height, false);
image.setImageBitmap(bMap2);
return true;
} catch (IOException e) {
Log.d("DownloadImage",e.toString());
return false;
}
}
I hope it will help. All the best. Happy Coding :)
Related
I'm trying to upload an image to the server using retrofit 2 multipart request and Gson parser
I tested the api by postman and its working fine but in android I'm getting the mentioned exception
Here's my code
this is retrofit dependency
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
Api Client
public class ApiClient {
public static final String BASE_URL = "http://www.AAbd.com/api/";
private static Retrofit retrofit = null;
public static Retrofit getClient() {
if (retrofit==null) {
Gson gson = new GsonBuilder()
.create();
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
return retrofit;
}
}
Api Interface
#POST("edit/Image")
#Multipart
Call<AuthModel> addImage (#Part("api_token") RequestBody api_token,
#Part("image") MultipartBody.Part image);
Model
#Expose
#SerializedName("api_token_status")
private String api_token_status;
#Expose
#SerializedName("status")
private String status;
#Expose
#SerializedName("message")
private String message;
public String getMessage() {
return message;
}
public String getApi_token_status() {
return api_token_status;
}
public String getStatus() {
return status;
}
Calling the request
public void addImageRequest (Bitmap image) {
try {
File f = new File(getCacheDir(), "offf");
f.createNewFile();
Bitmap bitmap = image;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 0 /*ignored for PNG*/, bos);
byte[] bitmapdata = bos.toByteArray();
FileOutputStream fos = new FileOutputStream(f);
fos.write(bitmapdata);
fos.flush();
fos.close();
RequestBody reqFile = RequestBody.create(MediaType.parse("image/*"), f);
MultipartBody.Part body = MultipartBody.Part.createFormData("image", f.getName(), reqFile);
RequestBody tokenRequest = RequestBody.create(MediaType.parse("text/plain"), token2);
apiInterface = ApiClient.getClient().create(ApiInterface.class);
Call<AuthModel> call = apiInterface.addImage(tokenRequest, body);
call.enqueue(new Callback<AuthModel>() {
#Override
public void onResponse(Call<AuthModel> call, Response<AuthModel> response) {
AuthModel result = response.body();
if(result != null) {
String status = result.getStatus();
String msg = result.getMessage();
if(status.equals("true")) {
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG).show();
Log.e("errorIs", msg);
} else {
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG).show();
Log.e("errorIs", msg);
}
} else {
try {
//Toast.makeText(context, response.errorBody().string() , Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void onFailure(Call<AuthModel> call, Throwable t) {
Toast.makeText(MainActivity.this, t.toString(), Toast.LENGTH_LONG).show();
}
});
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
I checked all the previous questions regarding this issue but I didn't find a possible solution for my case. Please help and thanks in advance
I am new to android .
I want to upload image as form data using Retrofit Post method.
I am using com.squareup.retrofit2:retrofit:2.3.0
This is my request body.
**Make interface like this add "MultipartBody.Part" in request and set your image path as post method and you can upload image using retrofit use this networkclient class to create retrofit instance **
public class NetworkClient {
private static final String BASE_URL = "";
private static Retrofit retrofit;
public static Retrofit getRetrofitClient(Context context) {
if (retrofit == null) {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.build();
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
public interface UploadAPIs {
#Multipart
#POST("/upload")
Call<ResponseBody> uploadImage(#Part MultipartBody.Part file, #Part("name") RequestBody requestBody);
}
private void uploadToServer(String filePath) {
Retrofit retrofit = NetworkClient.getRetrofitClient(this);
UploadAPIs uploadAPIs = retrofit.create(UploadAPIs.class);
//Create a file object using file path
File file = new File(filePath);
// Create a request body with file and image media type
RequestBody fileReqBody = RequestBody.create(MediaType.parse("image/*"), file);
// Create MultipartBody.Part using file request-body,file name and part name
MultipartBody.Part part = MultipartBody.Part.createFormData("upload", file.getName(), fileReqBody);
//Create request body with text description and text media type
RequestBody description = RequestBody.create(MediaType.parse("text/plain"), "image-type");
//
Call call = uploadAPIs.uploadImage(part, description);
call.enqueue(new Callback() {
#Override
public void onResponse(Call call, Response response) {
}
#Override
public void onFailure(Call call, Throwable t) {
}
});
}
Try this
#Multipart
#POST(Global.updateProfilePicture)
Call<YOUR_RESPONSE_MODEL> updatePicture(#Header("Authorization") String authorization, #PartMap Map<String, RequestBody> params);
And API call should be like this
public void updatePic(String senderID, String receiverID, String type, File photo) {
mProgressDialog.show();
final Map<String, RequestBody> map = new HashMap<>();
try {
RequestBody fileBody = RequestBody.create(MediaType.parse("multipart/form-data"), photo);
map.put("image\"; filename=\"" + photo.getName() + "\"", fileBody);
} catch (Exception e) {
e.printStackTrace();
}
map.put("sender_id", RequestBody.create(MediaType.parse("multipart/form-data"), senderID));
map.put("receiver_id", RequestBody.create(MediaType.parse("multipart/form-data"), receiverID));
map.put("type", RequestBody.create(MediaType.parse("multipart/form-data"), type));
Call<YOUR_RESPONSE_MODEL> call = mApiInterface.updatePicture(ACCESS_TOKEN, map);
call.enqueue(new Callback<YOUR_RESPONSE_MODEL>() {
#Override
public void onResponse(#NonNull Call<YOUR_RESPONSE_MODEL> call, #NonNull Response<YOUR_RESPONSE_MODEL> response) {
if (mContext != null) {
mProgressDialog.dismiss();
// Dismiss Dialog
}
}
#Override
public void onFailure(#NonNull Call<YOUR_RESPONSE_MODEL> call, #NonNull Throwable t) {
if (mContext != null) {
mProgressDialog.dismiss();
}
}
});
}
I got output by doing request as following
UploadAPI Interface
`
#Multipart
#Headers({"TOKEN:XXXX"})
#POST("/api/messages/image")Call<ImageResult>uploadImage(#Part("sender_id")RequestBody sender_id,#Part("receiver_id")RequestBody receiver_id,#Part("type")RequestBody type,#Part MultipartBody.Part image);`
And Following is Method Code, I tried
`
private void uploadToServer(String filePath)
{
Retrofit retrofit = NetworkClient.getRetrofitClient(this, sendImageMsgURL);
UploadAPIs uploadAPIs = retrofit.create(UploadAPIs.class);
File file = new File(filePath);
MultipartBody.Part requestImage = null;
RequestBody requestFile = RequestBody.create(MediaType.parse("mutlipart/form-
data"),file);
requestImage = MultipartBody.Part.createFormData("image", file.getName(), requestFile);
RequestBody sender_id = RequestBody.create(MediaType.parse("multipart/form-data"),
currentID);
RequestBody receiver_id = RequestBody.create(MediaType.parse("multipart/form-data"),
otherID);
RequestBody type = RequestBody.create(MediaType.parse("multipart/form-data"), "image");
Call<ImageResult> call = uploadAPIs.uploadImage(sender_id, receiver_id, type,
requestImage);
call.enqueue(new Callback<ImageResult>()
{
private Call<ImageResult> call;
private Response<ImageResult> response;
#Override
public void onResponse(Call<ImageResult> call, Response<ImageResult> response)
{
this.call = call;
this.response = response;
}
#Override
public void onFailure(Call call, Throwable t) {
Log.d("Error--------- :", t.getMessage());
}
});
}`
This is the code im using for multiple uploads to server.This format is working fine in POSTMAN and not working in by using retrofit2. Can anybody help me
#Multipart
#POST("/api/answers/save")
Call<ResponseBody> upload(#Header("Authorization") String
authorization,#Part("input_answer") RequestBody answer_string,#Part
List<MultipartBody.Part> files);
check this
#NonNull
private RequestBody createPartFromJsonString(String json_answers_string) {
return RequestBody.create(
okhttp3.MultipartBody.FORM, json_answers_string);
}
check this , using this for converting file to multipart body
#NonNull
private MultipartBody.Part prepareFilePart(String attachment_name, String absolute_path) {
File file = new File(absolute_path);
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
return MultipartBody.Part.createFormData(attachment_name, file.getName(), requestFile);
}
This is used for multiple uploads
private void multipartUploadAudit(JSONObject json_object, List<String> FileNameWithAbsolutePath) {
progressBar.setVisibility(View.VISIBLE);
//convert jsonobject to string
Gson gson = new Gson();
String answers_string_json_obj = gson.toJson(json_object);
APIService mAPIService = ApiUtils.getAPIService();
List<MultipartBody.Part> parts = new ArrayList<>();
// add dynamic
for (int i = 0; i < FileNameWithAbsolutePath.size(); i++) {
String name = FileNameWithAbsolutePath.get(i).substring(FileNameWithAbsolutePath.get(i).lastIndexOf("/") + 1);
String names[] = name.split("\\.");
parts.add(prepareFilePart(names[0], FileNameWithAbsolutePath.get(i)));
}
// add another part within the multipart request
RequestBody answer_string = createPartFromJsonString(answers_string_json_obj);
// finally, execute the request
Call<ResponseBody> call = mAPIService.upload("Bearer " + sharedPrefUserData.getUserData().getAuthToken(), answer_string, parts);
// Call<ResponseBody> call = mAPIService.upload( description, parts);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
progressBar.setVisibility(View.GONE);
if (response.isSuccessful()) {
response.body(); // do something with that
Toast.makeText(AuditQuestionsLandingScreen.this, response.body().toString(), Toast.LENGTH_SHORT).show();
} else {
response.errorBody(); // do something with that
Toast.makeText(AuditQuestionsLandingScreen.this, response.errorBody().toString(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
progressBar.setVisibility(View.GONE);
internetConnectionChecker.serverErrorAlert();
Log.v("Upload_error:", t.getMessage());
Toast.makeText(AuditQuestionsLandingScreen.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
After long struggle i got my answer. i made a mistake by converting jsonobject to string by using gson. it added enveloped my string with
{"nameValuePairs": {}}
so i used this.
RequestBody.create(MediaType.parse("multipart/form-
data"),String.valueOf(json_object))
I am new to use Retrofit and I want to send byte array of any file to the server by i always get Failed response from server, and I successfully post file using Volley and HttpUrlConnection both. Now please help me, this is my code snippet .
public class ApiClientPost {
private static final String BASE_URL = "http://BASE.URL/api/";
private static Retrofit retrofit = null;
public static Retrofit getClient(){
if(retrofit == null){
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
public interface ApiInterface {
#Multipart
#Headers({
"content-type: multipart/form-data"
})
#POST("eclaims/UploadFiles")
Call<JsonElement> UploadFiles(#Part MultipartBody.Part body);
}
FileInputStream fin = null;
try {
fin = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fin);
DataInputStream dis = new DataInputStream(bis);
fileContent = toByteArray(dis);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
MediaType mediaType = MediaType.parse("video/mp4");
RequestBody requestFile =
RequestBody.create(mediaType,
file
);
MultipartBody.Part body =
MultipartBody.Part.createFormData("", file.getName(),
requestFile);
ApiInterface apiInterface =
ApiClientPost.getClient().create(ApiInterface.class);
Call<JsonElement> uploadFile = apiInterface.UploadFiles(body);
uploadFile.enqueue(new Callback<JsonElement>() {
#Override
public void onResponse(Call<JsonElement> call,
Response<JsonElement> response) {
if (response.isSuccessful()) {
JsonElement mainResponse = response.body();
Log.d("Response ===", mainResponse.toString());
} else {
Log.e("Response ===", "Failed");
}
}
#Override
public void onFailure(Call<JsonElement> call, Throwable t) {
Log.e("Failed ===", t.getMessage());
}
});
Sorry I am unable to give to URL. It have sensitive data. But i always get failed response from server when i convert a image or video file to byte array and send that byte array to server.
You don't need to convert it to file, you can pass the byte[] immediately.
public static MultipartBody.Part toMultiPartFile(String name, byte[] byteArray) {
RequestBody reqFile = RequestBody.create(MediaType.parse("video/mp4"), byteArray);
return MultipartBody.Part.createFormData(name,
null, // filename, this is optional
reqFile);
}
I want to upload a binary file to the server in Android. I test Api method by postman:
And it's OK, as you see there is another option which you can upload files as form data(key, value):
Every tutorials (like this one)describe how to upload files as multipart/form-data:
// create RequestBody instance from file
RequestBody requestFile =
RequestBody.create(MediaType.parse("multipart/form-data"), file);
// MultipartBody.Part is used to send also the actual file name
MultipartBody.Part body =
MultipartBody.Part.createFormData("picture", file.getName(), requestFile);
I search a lot but couldn't find any way to upload file as binary with retrofit2.
There is just one Issue in retrofit repository which ask How can I POST a image binary in retrofit 2.0 beta?. I use its solution :
API Service:
#POST("trip/{tripId}/media/photos")
Call<MediaPost> postEventPhoto(
#Path("eventId") int tripId,
#Header("Authorization") String accessToken,
#Query("direction") String direction,
#Body RequestBody photo);
Caller:
InputStream in = new FileInputStream(new File(media.getPath()));
byte[] buf;
buf = new byte[in.available()];
while (in.read(buf) != -1);
RequestBody requestBody = RequestBody
.create(MediaType.parse("application/octet-stream"), buf);
Call<MediaPost> mediaPostCall = tripApiService.postTripPhoto(
tripId,
((GlobalInfo) getApplicationContext()).getApiAccessToken(),
direction,
requestBody);
But I got this error:
java.lang.IllegalArgumentException: #Body parameters cannot be used with form or multi-part encoding.
What's wrong with my code? what should I do?
Just adding another solution, as I had to dig a bit to understand what happened in the question in the first place.
My solution is to get the binary file as a byte[] directly and then put it inside the RequestBody. So in the end, the code would look like this:
interface RetrofitService {
#POST("api/v1/upload_file")
Call<Void> uploadBinaryFile(#Body RequestBody body);
}
And to call it:
public void uploadBinaryFile(File fileToUpload) {
retrofitService
.uploadBinaryFile(RequestBody.create(MediaType.parse("application/octet"),
Files.readAllBytes(fileToUpload));
}
This is basically the same as OP's original question, but just for the sake of clarity I'll leave this answer as well for the next reader.
After hours of searching I found that there was an #Multipart annotation remains in API interface of my code from last example! which prevent to send binary data to the server and the solution in retrofit repository was OK!
In Kotlin you can do this:
val file: File = retrieveMyJavaFile()
val requestBody: RequestBody = file.asRequestBody("application/octet-stream".toMediaTypeOrNull())
val response: MyResponse = myAPI.uploadPhoto(requestBody).body()!!
I had same problem, I wanted to upload binary file(image). The API was of Wordpress
I followed the solution code which is given at the end of this issue
Here is my little modified code
#POST("wp-json/wp/v2/media/")
Call<ImagePostResult> postEventPhoto(
#Header("Authorization") String accessToken,
#Header("Content-Type") String contentType,
#Header("Content-Disposition") String contentDisposition,
#Body RequestBody photo);
Here is the request
// For BasicAuth
String authHeader = getAuthHeader();
String contentType = "application/binary";
String contentDisposition = "attachment; filename = " + fileName;
RequestBody requestBodyee = null;
try {
InputStream in = new FileInputStream(file);
byte[] buf;
buf = new byte[in.available()];
while (in.read(buf) != -1) ;
requestBodyee = RequestBody
.create(MediaType.parse("application/octet-stream"), buf);
} catch (IOException e) {
e.printStackTrace();
}
Call<ImagePostResult> imagePostResultCall = apiInterface.postEventPhoto(
authHeader,
contentType,
contentDisposition,
requestBodyee);
imagePostResultCall.enqueue(new Callback<ImagePostResult>() {
#Override
public void onResponse(Call<ImagePostResult> call, Response<ImagePostResult> response) {
// Response Success
if (response.isSuccessful()) {
// yaay
}
}
#Override
public void onFailure(Call<ImagePostResult> call, Throwable t) {
Log.d(TAG, "onFailure: " + t);
}
});
You can also send the image in
//Api Interface
#Part MultipartBody.Part body
//Call in activity
file = FileUtils.getFile(this, uri);
reqFile = RequestBody.create(MediaType.parse("image/*"), file);
body = MultipartBody.Part.createFormData("uploaded_file", "Img_" + "_" + rightNow.getTimeInMillis() + ".jpg", reqFile);
just MediaType == Null
my code:
private fun put(uploadUrl : String , localPath : String) {
val file = File(localPath)
val byteArray = file2Byte(localPath)!!
val responseBody = RequestBody.create(null , byteArray)
val call = HttpFactory.providerUp.up(uploadUrl , responseBody)
call.enqueue(object : Callback<ResponseBody> {
override fun onFailure(call : retrofit2.Call<ResponseBody>? , t : Throwable?) {
LogUtil.toast("Failure")
}
override fun onResponse(call : retrofit2.Call<ResponseBody>? , response : retrofit.Response<ResponseBody>?) {
if (response!!.code() == 200) {
LogUtil.toast("YES")
} else {
LogUtil.toast("NO")
}
}
})
}
#PUT
fun up2(#Url url : String ,#Body requestBody : RequestBody ) : Call<ResponseBody>
I am upload image to server same like this but in volley ,Here is my code
Hope this is helpfull for someone
public void uploadImageToServer(byte[] value) {
final StringRequest stringRequest = new StringRequest(Request.Method.PUT,uploadImageURL,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.e("s3 response", response);
Toast.makeText(context, "Image Uploaded to Server", Toast.LENGTH_LONG).show();
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("error response", error.toString());
Toast.makeText(context, "Image Not Uploaded", Toast.LENGTH_LONG).show();
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headerMap = new HashMap<String, String>();
headerMap.put("header1", "header value");
headerMap.put("header2", "header value");
headerMap.put("Content-Type", "image/jpeg");
Log.e("header", headerMap.toString());
return headerMap;
}
#Override
public byte[] getBody() throws AuthFailureError {
return value;
}
};
{
int socketTimeout = 30000;
RetryPolicy policy = new DefaultRetryPolicy(socketTimeout, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
stringRequest.setRetryPolicy(policy);
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.getCache().clear();
requestQueue.add(stringRequest);
}
}
If any android developer want to upload file over the server using binary data with the help of volley.
public void uploadImageToServer (byte[] imageByte) {
final StringRequest stringRequest = new StringRequest(Request.Method.POST,uploadImageURL,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.e("s3 response", response);
Toast.makeText(context, "Image Uploaded to Server", Toast.LENGTH_LONG).show();
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("error response", error.toString());
Toast.makeText(context, "Image Not Uploaded", Toast.LENGTH_LONG).show();
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headerMap = new HashMap<String, String>();
headerMap.put("header1", "header value");
headerMap.put("Content-Type", "image/jpeg");
return headerMap;
}
#Override
public byte[] getBody() throws AuthFailureError {
//Binary value data
return value;
}
};
{
int socketTimeout = 30000;
RetryPolicy policy = new DefaultRetryPolicy(socketTimeout, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
stringRequest.setRetryPolicy(policy);
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.getCache().clear();
requestQueue.add(stringRequest);
}
}
//You can convert any file to byte array
public static byte[] convertFileToBytes(File file)
{
int size = (int) userImageFile.length();
byte[] bytes = new byte[size];
try {
BufferedInputStream buf = new BufferedInputStream(new FileInputStream(userImageFile));
buf.read(bytes, 0, bytes.length);
buf.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
return bytes;
}