OkHttp image type - android

When I upload an image okHttp only accepts PNG? When I try jpg it denies.
This is my code:
public static Boolean uploadFile(final File file, final Context context) {
AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
#Override
public void run() {
try {
final MediaType MEDIA_TYPE_JPG = MediaType.parse("image");
//employee verkrijgen
DataLayer dataLayer = new DataLayer(context);
Employee employee = dataLayer.getEmployee();
dataLayer.close();
//request body aanmaken
RequestBody formBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("ProfilePicture", file.getName(),
RequestBody.create(MEDIA_TYPE_JPG,file))
.addFormDataPart("api_token", employee.getApiToken())
.build();
Request request = new Request.Builder().url(static_urls.Employee.uploadProfilePicture(employee.getEmployeeId())).post(formBody).build();
OkHttpClient client = new OkHttpClient();
Response response = client.newCall(request).execute();
String responseString = response.body().string().substring(5000, response.body().string().length());
}
catch(Exception ex)
{
Log.e("upload",Log.getStackTraceString(ex));
}
}
});
return false;
}
What am I doing wrong?

use
MediaType.parse("image/jpeg");
Here is full list of mime types

Related

How to post byte array using Retrofit 2

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);
}

Glide POST request for image

I'm trying to download image from server with POST (json body). To accomplish that I created okhttp interceptor:
private static class PostThumbnailRequestInterceptor implements Interceptor {
private static final String DEVICE_GUID = "device_guid";
private static final String RESOURCE_GUIDS = "resource_guids";
private static final String UTC_TIMESTAMP = "utc_timestamp";
private String mChannelGuid;
private String mResourceGuid;
public PostThumbnailRequestInterceptor(String channelGuid, String resourceGuid) {
mChannelGuid = channelGuid;
mResourceGuid = resourceGuid;
}
#Override
public Response intercept(Chain chain) throws IOException {
final MediaType JSON
= MediaType.parse("application/json; charset=utf-8");
JSONArray resources = new JSONArray();
resources.put(mResourceGuid);
JSONObject requestedThumbnail = new JSONObject();
JSONObject payload = new JSONObject();
try {
requestedThumbnail.put(UTC_TIMESTAMP, System.currentTimeMillis() * 1000);
requestedThumbnail.put(DEVICE_GUID, mChannelGuid);
requestedThumbnail.put(RESOURCE_GUIDS, resources);
payload.put("thumbnails", new JSONArray() {{put(requestedThumbnail);}});
} catch (JSONException e) {
throw new IOException("Failed to create payload");
}
RequestBody body = RequestBody.create(JSON, payload.toString());
final Request original = chain.request();
final Request.Builder requestBuilder = original.newBuilder()
.url(original.url())
.post(body);
//return chain.proceed(requestBuilder.build());
Response response = chain.proceed(requestBuilder.build());
try {
MediaType contentType = MediaType.parse("data:image/jpeg;base64");// response.body().contentType();
JSONObject object = new JSONObject(response.body().string());
String base64String = object.optJSONArray("thumbnails").getJSONObject(0).optString("content");
base64String = base64String.replace("data:image/jpeg;base64,", "");
byte[] rawImage = Base64.decode(base64String , Base64.DEFAULT);
ResponseBody realResponseBody = ResponseBody.create(contentType, rawImage);
response = response.newBuilder().body(realResponseBody).build();
} catch (JSONException e) {
e.printStackTrace();
}
return response;
}
}
And using it like this
OkHttpClient mOkHttpClient = new OkHttpClient.Builder()
.addInterceptor(new PostThumbnailRequestInterceptor(channel.id.getServerId(), channel.id.getChannelId()))
.build();
GlideApp.get(getContext())
.getRegistry().replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(mOkHttpClient));
It is works well with 1 request per time, but if I bind it with recycler view, replacing classes in Glide with dynamic interceptor produce a lot of errors (failed to load resource).
Am I on right way to request post or it is only 1 way - firstly request as usual and then pass decoded bytes to Glide?

How do I make a post request? I use OkHttp? no server response

I need to post a message to server.
- MediaType : application/x-www-form-urlencoded
So, I used FormEncodingBuilder class for making body.
I wrote this code.
Uri.Builder uri = new Uri.Builder()
.scheme(SCHEME)
.encodedAuthority(HOST)
.appendPath("v3")
.appendPath("svc")
.appendPath("auth");
FormEncodingBUilderformBody = new FormEncodingBUilder()
.add("name", data.getName())
.add("gender", data.getGender())
.build();
Request request = new Request.Builder()
.url(uri.build().toString())
.post(formBody)
.build();
try {
Response response = mHttpClient.newCall(request).execute();
String body = response.body().string();
return body;
} catch (Exception e) {
throw new ApiException(0, e.toString());
}
but server didn't read parameter.
So, server request parameter's value.
How do I make message?
Maybe you need to set charset.
but FormEncodingBuilder class use only MediaType "application/x-www-form-urlencoded".
So, you can make new class like FormEncodingBuilder.
public class OkHttpFormBuilder {
private MediaType CONTENT_TYPE = MediaType.parse("application/x-www-form-urlencoded;charset=utf-8");
private final StringBuilder content = new StringBuilder();
public OkHttpFormBuilder() {
}
public MediaType getCONTENT_TYPE() {
return CONTENT_TYPE;
}
public void setCONTENT_TYPE(MediaType CONTENT_TYPE) {
this.CONTENT_TYPE = CONTENT_TYPE;
}
public OkHttpFormBuilder add(String name, String value) {
if(this.content.length() > 0) {
this.content.append('&');
}
try {
this.content.append(URLEncoder.encode(name, "UTF-8")).append('=').append(URLEncoder.encode(value, "UTF-8"));
return this;
} catch (UnsupportedEncodingException var4) {
throw new AssertionError(var4);
}
}
public String getContent()
{
return this.content.toString();
}
public RequestBody build() {
if(this.content.length() == 0) {
throw new IllegalStateException("Form encoded body must have at least one part.");
} else {
byte[] contentBytes = this.content.toString().getBytes(Util.UTF_8);
return RequestBody.create(CONTENT_TYPE, contentBytes);
}
}}
After you make formbody using this class, try send to server

Retrofit 2 file down/upload

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 :)

Uploading a large file in multipart using OkHttp

What are my options for uploading a single large file (more specifically, to s3) in multipart in Android using OKhttp?
Get OkHttp 2.1, and use MultipartBuilder.addFormDataPart() which takes the filename as a parameter.
/**
* Upload Image
*
* #param memberId
* #param sourceImageFile
* #return
*/
public static JSONObject uploadImage(String memberId, String sourceImageFile) {
try {
File sourceFile = new File(sourceImageFile);
Log.d(TAG, "File...::::" + sourceFile + " : " + sourceFile.exists());
//Determining the media type
final MediaType MEDIA_TYPE = sourceImageFile.endsWith("png") ?
MediaType.parse("image/png") : MediaType.parse("image/jpeg");
RequestBody requestBody = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addFormDataPart("member_id", memberId)
.addFormDataPart("file", "profile.png", RequestBody.create(MEDIA_TYPE, sourceFile))
.build();
Request request = new Request.Builder()
.url(URL_UPLOAD_IMAGE)
.post(requestBody)
.build();
OkHttpClient client = new OkHttpClient();
Response response = client.newCall(request).execute();
return new JSONObject(response.body().string());
} catch (UnknownHostException | UnsupportedEncodingException e) {
Log.e(TAG, "Error: " + e.getLocalizedMessage());
} catch (Exception e) {
Log.e(TAG, "Other Error: " + e.getLocalizedMessage());
}
return null;
}
#Edited for okhttp3:
compile 'com.squareup.okhttp3:okhttp:3.4.1'
RequestBody replaced by:
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("uploaded_file", filename, RequestBody.create(MEDIA_TYPE_PNG, sourceFile))
.addFormDataPart("result", "my_image")
.build();
#Uploaded Demo on GITHUB:
##I have added my answer for Multiple Image Upload :)
From the OkHttp Recipes page, this code uploads an image to Imgur:
private static final String IMGUR_CLIENT_ID = "...";
private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
// Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image
RequestBody requestBody = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"title\""),
RequestBody.create(null, "Square Logo"))
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"image\""),
RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png")))
.build();
Request request = new Request.Builder()
.header("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
.url("https://api.imgur.com/3/image")
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
You'll need to adapt this to S3, but the classes you need should be the same.
For okhttp 4.* use the MultipartBody.Builder:
fun postMultipart(url: String, text: String, imagePath: String, imageFileName: String): okhttp3.Response? {
val file = File(imagePath)
val fileRequestBody = file.asRequestBody("image/jpeg".toMediaType())
val requestBody = MultipartBody.Builder()
.addFormDataPart("text", text)
.addFormDataPart("image", imageFileName, fileRequestBody)
.build()
val request = getRequestBuilder(url)
.post(requestBody)
.build()
val client = OkHttpClient()
client.newCall(request).execute().use { response ->
return response
}
}
for okhttp 2.6.0 {
try {
File file = new File(Environment.getExternalStorageDirectory().getPath()+"/xxx/share/" + "ic_launcher.png");
String contentType = file.toURL().openConnection().getContentType();
RequestBody fileBody = RequestBody.create(MediaType.parse(contentType), file);
RequestBody requestBody = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addFormDataPart("fileUploadType","1")
.addFormDataPart("miniType",contentType)
.addFormDataPart("ext",file.getAbsolutePath().substring(file.getAbsolutePath().lastIndexOf(".")))
.addFormDataPart("fileTypeName","img")
.addFormDataPart("Filedata","ss.png",fileBody)
.build();
Request request = new Request.Builder()
.url(Contains.MULTIPARTY_POST)
.post(requestBody)
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
runOnUiThread(new Runnable() {
#Override
public void run() {
tvGetNews.setText("upload fail");
}
});
}
#Override
public void onResponse(Response response) throws IOException {
runOnUiThread(new Runnable() {
#Override
public void run() {
tvGetNews.setText("upload success");
}
});
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
In Android you usally part from an Uri. The problem when using large files is that you easily run into OutOfMemoryError if you try to read the full stream to a byte array (everything in memory) or you end up creating useless files with Uri stream. This is because RequestBody doesn't support creation from Stream (because sometimes OkHttp needs to read it many times, if you get a 30X redirect for instance) or Uri (because OkHttp is not an Android library).
But OkHttp provides the library Okio, with convenient classes emulating Streams (Source and Sink) and more convenient internal usage.
So, to create a BodyRequest form an Uri avoiding any OutOfMemoryError due to large files create it this way:
private static final MediaType MULTIPART_FOR_DATA = MediaType.parse("multipart/form-data");
private #NotNull RequestBody getFilePart(Uri largeFileUri) {
return new RequestBody() {
#Override
public MediaType contentType() {
return MULTIPART_FOR_DATA;
}
#Override
public void writeTo(#NotNull BufferedSink sink) throws IOException {
try (Source source = Okio.source(context.getContentResolver().openInputStream(mediaUri))) {
sink.writeAll(source);
}
}
};
}
Thank you to everyone posting and commenting in the folowing GitHub thread https://github.com/square/okhttp/issues/3585

Categories

Resources