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;
}
Related
I wanted to upload a file from my android internal storage to Any cloud storage(ex.google drive,One drive etc)since kloudless provides an api to upload file to any cloud storage using accesstoken I wanted to use the same api for uploading the file (https://api.kloudless.com/v1/accounts/accountid+/storage/files/).
I tried it through postman I am able to upload the file
Now I tried through android volley I am able to create the file in the cloud but there is no data inside it. Here is my code
public class MainActivity extends AppCompatActivity {
Button b;
TextView TV;
File myFile;
String responseString;
String path;
public String BASE_URL = "https://api.kloudless.com";
private static final int FILE_SELECT_CODE = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TV = findViewById(R.id.textView);
b = findViewById(R.id.button);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
showFileChooser();
}
});
}
private void showFileChooser() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);
try {
startActivityForResult(
Intent.createChooser(intent, "Select a File to Upload"),
FILE_SELECT_CODE);
} catch (android.content.ActivityNotFoundException ex) {
// Potentially direct the user to the Market with a Dialog
Toast.makeText(this, "Please install a File Manager.",
Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == FILE_SELECT_CODE) {
if (resultCode == RESULT_OK) {
// Get the Uri of the selected file
Uri uri = data.getData();
Log.d("TAG", "File Uri: " + uri.toString());
// Get the path
String path = null;
try {
path = FileUtils.getPath(this, uri);
} catch (URISyntaxException e) {
e.printStackTrace();
}
Log.d("TAG", "File Path: " + path);
try {
data();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
super.onActivityResult(requestCode, resultCode, data);
}
public void data() throws FileNotFoundException, UnsupportedEncodingException {
final String url = BASE_URL + "/v1/accounts/" + "accountid" + "/storage/files/";
final RequestQueue queue = Volley.newRequestQueue(this);
HashMap<String, Object> params = new HashMap<String, Object>();
params.put( "file","somedata");
JSONObject Body=new JSONObject(params);
final JsonObjectRequest request = new JsonObjectRequest(Request.Method.POST, url,Body, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
// response
Log.d("Response", response.toString());
}
},
new ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// error
Log.d("Error.Response", error.toString());
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> params = new HashMap<String, String>();
params.put("Authorization", "Bearer Bearerkey");
params.put("Content-Type", "form-data");
params.put("X-Kloudless-Metadata", "{\"parent_id\":\"root\",\"name\":\"testdone.txt\"}");
// params.put("Content-Length", Space);
return params;
}
};
queue.add(request);
}
Please help me how to send the file in body of my request
I work at Kloudless and while I am not very familiar with the Android Volley, the issue here appears to be that you are setting a JSON body with the incorrect content type. In order to replicate the Postman request, you would need to use a multipart file upload instead, as described here: How to upload file using Volley library in android? The file would need to be added to a field called file, e.g entity.addPart("file", new FileBody(new File("....")));
In order for there to be more efficient handling on the server side (for larger files), the request performed should instead include the binary file contents in the request body and have the header Content-Type: application/octet-stream. Based on some cursory searching, it seems like the Volley library doesn't make that very easy so it might be best to try a different library.
Finally found the simple solution to upload a file to api
RequestQueue queue = Volley.newRequestQueue(this);
String url = BASE_URL + "/v1/accounts/" + "353284419" + "/storage/files/";
StringRequest postRequest = new StringRequest(Request.Method.POST, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Toast.makeText(MainActivity.this, response, Toast.LENGTH_LONG).show();
// response
Log.d("Response", response);
}
},
new ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// error
Log.d("Error.Response", error.toString());
}
}
) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("Authorization", "Bearer ix7wW4CFJsHxhttg42qsO6HNNRPh06");
params.put("Content-Type", "application/octet-stream");
params.put("X-Kloudless-Metadata", "{\"parent_id\":\"root\",\"name\":\"testing uplodes.pdf\"}");
// params.put("Content-Length", Space);
return params;
}
#Override
public byte[] getBody() throws com.android.volley.AuthFailureError {
File f=new File(path);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
FileInputStream fis = null;
try {
fis = new FileInputStream(f);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
byte[] bytesArray = new byte[(int)f.length()];
try {
fis.read(bytesArray);
} catch (IOException e) {
e.printStackTrace();
}
return bytesArray;
};
};
postRequest.setRetryPolicy(new DefaultRetryPolicy(
40000,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
queue.add(postRequest);
}
just convert the file into binary array and send it in the body
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've been looking for a way to upload a file using Volley API using the PUT method. All I've seen so far are through MultiPart POST method which aren't applicable to my case.
Assuming I can't change anything on the server side and I'm stuck with using PUT. How do I achieve this in volley?
Note that I only have the url where to upload the file and the file itself.
For uploading image file add the following functions to your StringRequest object.
Here outputFileUri is the Uri of the file which you want to upload.
#Override
public String getBodyContentType() {
return "image/jpeg";
}
#Override
public byte[] getBody() throws AuthFailureError {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
InputStream inputStream = mContext.getContentResolver().openInputStream(outputFileUri);
byte[] b = new byte[8192];
for (int readNum; (readNum = inputStream.read(b)) != -1; ) {
bos.write(b, 0, readNum);
}
inputStream.close();
return bos.toByteArray();
} catch (Exception e) {
Log.d(TAG, e.toString());
}
return null;
}
use the basic concept of PUT method
url = "your URL";
StringRequest putRequest = new StringRequest(Request.Method.PUT, url,
new Response.Listener<String>()
{
#Override
public void onResponse(String response) {
// response
Log.d("Response", response);
}
},
new Response.ErrorListener()
{
#Override
public void onErrorResponse(VolleyError error) {
// error
Log.d("Error.Response", response);
}
}){
#Override
protected Map<String, String> getParams()
{
Map<String, String> params = new HashMap<String, String> ();
params.put("name", "file_name");
return params;
}
}; RequestQueue queue = Volley.newRequestQueue(this);
queue.add(putRequest);
private void Dialog_profile_pic() {
// create upload service client
File file = new File(selectedImagePath);
// 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("memFile", file.getName(), requestFile);
// add another part within the multipart request
RequestBody description =
RequestBody.create(
MediaType.parse("multipart/form-data"), ApiResultCode.getApiKey());
RequestBody description2 =
RequestBody.create(
MediaType.parse("multipart/form-data"), ApiResultCode.getApiType());
Call<LoginPicture> loginPictureCall = RequestClient.getInstance()
.loginPicture(description, description2, body);
loginPictureCall.enqueue(new Callback<LoginPicture>() {
#Override
public void onResponse(Call<LoginPicture> call, Response<LoginPicture> response) {
//CONNECTION SUCCESS
LoginPicture NewUser = response.body();
if (NewUser.getResponsedata().getResultCode() == 100) {
Log.e("DEBUG", "CONNECTION result: CONGRATS");
} else {
Log.e("DEBUG", "CONNECTION result: " + NewUser.getResponsedata().getResultCode() + NewUser.getResponsedata().getResultMessage());
}
}
#Override
public void onFailure(Call<LoginPicture> call, Throwable t) {
//CONNECTION FAIL
Log.e("DEBUG", "CONNECTION result: FAIL" );
}
});
}
\
public interface ApiInterface {
#Multipart
#POST("/memberController/joinUploadProfile.json")
Call<LoginPicture> loginPicture(#Part("apiKey") RequestBody apiKey, #Part("apiType") RequestBody apiType, #Part("memFile") MultipartBody.Part file); //multi part
\
I am trying to pass in two string parameters and an image file using retrofit2 but I am failing to get a connection. Anyone can help me find what I need to do? I have been struggling over this for 2 days now.
//In Request Client API Interface
#Multipart
#POST("URL.json")
Call<LoginPicture> loginPicture(#PartMap() Map<String, RequestBody> mapPhoto); //multi part
//In activity
private void Dialog_profile_pic(final Uri selectedImageUri) {
// create upload service client
File file = new File(selectedImagePath);
HashMap<String, RequestBody> map = new HashMap<>();
RequestBody description =
RequestBody.create(
MediaType.parse("text/plain"),"content1");
RequestBody description2 =
RequestBody.create(
MediaType.parse("text/plain"), "content2");
// create RequestBody instance from file
RequestBody requestFile =
RequestBody.create(MediaType.parse("image/jpeg"), file);
map.put("memFile\"; filename=\""+file.getName(),requestFile);
map.put("apiKey",description);
map.put("apiType", description2);
Call<LoginPicture> loginPictureCall = RequestClient.getInstance()
.loginPicture(map);
loginPictureCall.enqueue(new Callback<LoginPicture>() {
#Override
public void onResponse(Call<LoginPicture> call, Response<LoginPicture> response) {
Picasso.with(Activity_create.this).load(NewUser.getResponsedata().getResultObject()).into(iv_profile_pic);
} else {
Log.e("DEBUG", "CONNECTION result: " + NewUser.getResponsedata().getResultCode() + NewUser.getResponsedata().getResultMessage());
}
}
#Override
public void onFailure(Call<LoginPicture> call, Throwable t) {
//통신 실패 시
Log.e("DEBUG", "CONNECTION result: FAIL");
}
});
}
//And it works now
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 :)