Retrofit @Body With @Multipart Having Issue

POST Multipart Form Data using Retrofit 2.0 including image

I am highlighting the solution in both 1.9 and 2.0 since it is useful for some

In 1.9, I think the better solution is to save the file to disk and use it as Typed file like:

RetroFit 1.9

(I don't know about your server-side implementation) have an API interface method similar to this

@POST("/en/Api/Results/UploadFile")
void UploadFile(@Part("file") TypedFile file,
@Part("folder") String folder,
Callback<Response> callback);

And use it like

TypedFile file = new TypedFile("multipart/form-data",
new File(path));

For RetroFit 2 Use the following method

RetroFit 2.0 ( This was a workaround for an issue in RetroFit 2 which is fixed now, for the correct method refer jimmy0251's answer)

API Interface:

public interface ApiInterface {

@Multipart
@POST("/api/Accounts/editaccount")
Call<User> editUser(@Header("Authorization") String authorization,
@Part("file\"; filename=\"pp.png\" ") RequestBody file,
@Part("FirstName") RequestBody fname,
@Part("Id") RequestBody id);
}

Use it like:

File file = new File(imageUri.getPath());

RequestBody fbody = RequestBody.create(MediaType.parse("image/*"),
file);

RequestBody name = RequestBody.create(MediaType.parse("text/plain"),
firstNameField.getText()
.toString());

RequestBody id = RequestBody.create(MediaType.parse("text/plain"),
AZUtils.getUserId(this));

Call<User> call = client.editUser(AZUtils.getToken(this),
fbody,
name,
id);

call.enqueue(new Callback<User>() {

@Override
public void onResponse(retrofit.Response<User> response,
Retrofit retrofit) {

AZUtils.printObject(response.body());
}

@Override
public void onFailure(Throwable t) {

t.printStackTrace();
}
});

Retrofit2 failed to upload image with Multipart or RequestBody

The issue were caused by inability to read the file from disk.

Adding android:requestLegacyExternalStorage="true" to the Android Manifest worked for me with Android sdk 29.

<application
android:name=".MyApplication"
android:requestLegacyExternalStorage="true" ...

Apart from adding <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> permission.

Andrioid Retrofit Multipart Image Upload 500 error

I have fixed issue. I have posted both params in single request body and changed param as @Part to @Body.


fun uploadImage(filepath: String) {
Log.e("info", ">>>>>status>>>>>" + ">>>>>>" + filepath)
val file = File(filepath)
Log.d("file...", "length..." + file.length())

val mimeType = getMimeType(file)
val metaobject = JSONObject()
metaobject.put("eye", "OD")



val requestBody: RequestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("metadata", metaobject.toString())
.addFormDataPart(
"file", file.name,
file.asRequestBody(mimeType!!.toMediaTypeOrNull())
)
.build()

val header = HashMap<String, String>()


header["Authorization"] =
"Bearer <<token>>"
val request = ApiService.buildService(ApiHelper::class.java)
val call = request.sendMediaFile(header,requestBody)
call.enqueue(
object : Callback<ResponseBody?> {
override fun onResponse(
call: Call<ResponseBody?>,
response: Response<ResponseBody?>
) {
Log.e("Upload", "success" + response.body().toString())
Log.e("Upload", "success" + response.errorBody().toString())

}

override fun onFailure(call: Call<ResponseBody?>, t: Throwable) {
Log.e("Upload error:", t.message!!)
}
})
}


and in helper class

@POST("{profileId}/files")
fun sendMediaFile(
@Path("profileId") profile_id: String,
@HeaderMap headers: Map<String, String>,
@Body metadata: RequestBody?
): Call<ResponseBody?>

Android having problems while uploading Images using Retrofit multipart?

Add this

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

inside the manifest tag of your manifest file.Makes sure its outside the application tag however.

Retrofit @Part Multipartbody.Part with @multipart throws exception

@Part MultipartBody.Part file. It throws Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $.

This is GSON error and it means that model that you provided does not match to response you received from your server (In your case you received plane string instead of JSON)

In order to solve your issue please post full response from server so as your model class

Retrofit 2 Multipart image upload with data

We test api in Postman... So my Create Post Answer includes (all Dynamic)

  • Headers
  • Simple Strings
  • Single Image
  • Array Of Images
  • Array Of Categories
  • Array Of Features

Almost all things

Below is the Postman image for api testing...
You will get clear concept of request

  • Headers Image

Sample Image

So for this ...
Below is my Api...

@POST("post-create")
Call<PostCreateResponse> getPostCreateBodyResponse(
@Header("Accept") String accept,
@Header("Authorization") String authorization,
@Body RequestBody file
);

Now Retrofit Client area--->

private Retrofit retrofit;

// This is Client
private RetrofitClient() {

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

httpClient.connectTimeout(100, TimeUnit.SECONDS);
httpClient.readTimeout(100,TimeUnit.SECONDS);
httpClient.writeTimeout(100,TimeUnit.SECONDS);
httpClient.addInterceptor(logging); // <-- this is the important line!

retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient.build())
.build();
}

This is the way I Made the Request...

/*
* -------------- Retrofit post Create single featured Image Working with MultipartBody -----------
* */

progressDialog.show();

MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);

builder.addFormDataPart("title", "3 room Current Free")
.addFormDataPart("location", "Dhaka")
.addFormDataPart("latitude", "23.7515")
.addFormDataPart("longitude", "90.3625")
.addFormDataPart("condition", "1")
.addFormDataPart("rent_amount", "123456")
.addFormDataPart("is_negotiable", "0")
.addFormDataPart("available_from", "2018-10-15");

// Categories
for (int categoryId : categories) {
builder.addFormDataPart("categories[]", String.valueOf(categoryId));
}
// Features
for (Integer featureId : features) {
builder.addFormDataPart("features[]", String.valueOf(featureId));
}

// featured Image
if (photoPaths.get(0) != null) {
File featured_image = new File(photoPaths.get(0));
if (featured_image.exists()) {

// If you want to use Bitmap then use this

Bitmap bmp = BitmapFactory.decodeFile(featured_image.getAbsolutePath());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.JPEG, 30, bos);

builder.addFormDataPart("featured_photo", featured_image.getName(), RequestBody.create(MultipartBody.FORM, bos.toByteArray()));


// If you want to use direct file then use this ( comment out the below part and comment the above part )

//builder.addFormDataPart("featured_photo", featured_image.getName(), RequestBody.create(MultipartBody.FORM, featured_image));
}
}

// Images
for (String photoPath : photoPaths) {
if (photoPath != null) {
File images = new File(photoPath);
if (images.exists()) {
builder.addFormDataPart("images[]", images.getName(), RequestBody.create(MultipartBody.FORM, images));
}
}
}

RequestBody requestBody = builder.build();
Call<PostCreateResponse> call = RetrofitClient.getInstance().getApi().getPostCreateBodyResponse(Accept, Authorization, requestBody);
call.enqueue(new Callback<PostCreateResponse>() {
@Override
public void onResponse(Call<PostCreateResponse> call, Response<PostCreateResponse> response) {
progressDialog.dismiss();
Log.d(TAG, "onResponse: response code: retrofit: " + response.code());
}

@Override
public void onFailure(Call<PostCreateResponse> call, Throwable t) {

}
});

/*
* ---------------- Retrofit post Create single featured Image Working with MultipartBody----------------
* */

I hope this will help you all... thanks

Multipart request with retrofit 2.0 Android Taking too much time to request

You can increase the timeouts in the Retrofit settings.

OkHttpClient okHttpClient = new OkHttpClient.Builder()  
.connectTimeout(1, TimeUnit.MINUTES)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.build();

Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl("http://10.0.2.2:3000/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create());

Maybe it help for you!

More: https://futurestud.io/tutorials/retrofit-2-customize-network-timeouts



Related Topics



Leave a reply



Submit