I'm trying to upload a file (picture) to the server using Retrofit 2. I'm following that tutorial which seems pretty easy at first, but didn't work in my case...
When I call the API function, i'm always getting this error:
W/System.err: java.lang.ArrayIndexOutOfBoundsException: length=1; index=1
W/System.err: at retrofit2.ServiceMethod$Builder.build(ServiceMethod.java:190)
W/System.err: at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:166)
W/System.err: at retrofit2.Retrofit$1.invoke(Retrofit.java:145)
W/System.err: at java.lang.reflect.Proxy.invoke(Proxy.java:393)
W/System.err: at com.plante.android.cobalt.fragment.FragmentIncidentPlan.uploadFile(FragmentIncidentPlan.java:575)
Here is my API call:
#Multipart
#POST(Constants.URL_UPLOAD)
Call<ResponseBody> upload(#Part RequestBody description,
#Part MultipartBody.Part file);
Here is the method I use to upload a file:
private void uploadFile(String path) {
// create upload service client
// use the FileUtils to get the actual file by uri
File file = new File(path);
Log.e(TAG, file.getAbsolutePath());
// 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);
// add another part within the multipart request
String descriptionString = "hello, this is description speaking";
RequestBody description =
RequestBody.create(
MediaType.parse("multipart/form-data"), descriptionString);
// finally, execute the request
Call<ResponseBody> call = cobaltServices.upload(description, body);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call,
Response<ResponseBody> response) {
Log.v("Upload", "success");
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.e("Upload error:", t.getMessage());
}
});
}
The Exceptions says that the first #Part doesn't needs a name in the annotation.
#Multipart
#POST(Constants.URL_UPLOAD)
Call<ResponseBody> upload(#Part RequestBody description,
#Part MultipartBody.Part file);
I fix my issue using this link : https://github.com/square/retrofit/issues/1063#issuecomment-145920568
This is the solution of the problem:
#Multipart
#POST ("/api/Events/editevent")
Call<Event> editEvent (#PartMap Map<String, RequestBody> params);
I call it by following way.
Map<String, RequestBody> map = new HashMap<>();
map.put("Id", AZUtils.toRequestBody(eventId));
map.put("Name", AZUtils.toRequestBody(titleView.getValue()));
if (imageUri != null) {
File file = new File(imageUri.getPath());
RequestBody fileBody = RequestBody.create(MediaType.parse("image/png"), file);
map.put("file\"; filename=\"pp.png\"", fileBody);
}
Call<Event> call = api.editEvent(map);
call.enqueue(new Callback<Event>() { }
The method toRequestBody just converts String into RequestBody
public static RequestBody toRequestBody (String value) {
RequestBody body = RequestBody.create(MediaType.parse("text/plain"), value);
return body ;
}
Related
Regards, I have to upload this data.
postman
And I have this code.
Customer Creation
public BeeMappingClient(String url){
retrofit= new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
conexion=retrofit.create(Conexion.class);
}
Interface
#Multipart
#POST("task")
Call<ResponsetTask> API_Task(#Header("Authorization") String key,
#Part MultipartBody.Part multipartImage,
#Part("message") RequestBody message ,
#Part("filecomment") RequestBody filecomment,
#Part("api_token") RequestBody api_token,
#Part("user_id") RequestBody user_id);
And call
File file=new File(path);
MultipartBody.Part[] multipartImageList = new MultipartBody.Part[1];
RequestBody surveyBody = RequestBody.create(MediaType.parse("image/*"), file);
multipartImageList[0] = MultipartBody.Part.createFormData("image", "image.jpg", surveyBody);
RequestBody message = RequestBody.create(MediaType.parse("message"), Constantes.MESSAGE);
RequestBody filecomment = RequestBody.create(MediaType.parse("filecomment"), Constantes.FILECOMMENT);
RequestBody api_token = RequestBody.create(MediaType.parse("api_token"),Constantes.api_token);
RequestBody user_id = RequestBody.create(MediaType.parse("user_id"), Integer.toString(Constantes.id));
Call<ResponsetTask> call = conexion.API_Task(Constantes.AUTH,multipartImageList[0],message,filecomment,api_token,user_id);
call.enqueue(new Callback<ResponsetTask>() {
#Override
public void onResponse(Call<ResponsetTask> call, Response<ResponsetTask> response) {
Constantes.api_task=response.body().getTaskId();
}
#Override
public void onFailure(Call<ResponsetTask> call, Throwable t) {
}
});
The problem is that it does nothing, if I do a debug all seems to be going well until it reaches the call.enqueu ... there I should enter OnResques or OnFailure but it does not just go to the end of the method as if it did not exist .
What should I do ?, this is the best method to upload this data ?.
I thank you in advance for any help or guidance you can give me.
Try this - for multipart request
In interface
#Multipart
#POST("task")
Call<ResponseBody> submitRegistration(#Part MultipartBody.Part body,
#Part("message") RequestBody message)
Pass values -
File file = new File(path);
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
MultipartBody.Part body = MultipartBody.Part.createFormData("image", file.getName(), requestFile);
RequestBody message = RequestBody.create(MediaType.parse("text/plain"), Constantes.MESSAGE);
Call -
Call<ResponseBody> call = service.callApi(body,message);
RequestBody surveyBody = RequestBody.create(MediaType.parse("multipart/form-data"), file);
Replace "image/*" with "multipart/form-data"
I'm using retrofit2, i was sending data through it using #FormUrlEncoded because everything was as a string even images but i faced some errors when i send collection of images as strings, so i changes to multipart.
Now i'm facing problem that i can't send #Field of string with multipart.
So, how i can solve this problem without using RequestBody for every string?
here's my code
#Multipart
#POST("/androidfiles/insertNews.php")
Call<ResponseBody> uploadImage(#Part MultipartBody.Part file, #Part("name") RequestBody name,
#Field("tArabic") String arabicTitle,
#Field("tEnglish") String englishTitle,
#Field("tRussian") String russianTitle,
#Field("tItalian") String italianTitle,
#Field("dArabic") String arabicDescription,
#Field("dEnglish") String englishDescription,
#Field("dRussian") String russianDescription,
#Field("dItalian") String italianDescription);
and here.
private void insertNews(Uri uri){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ServiceConstants.URL)
.build();
File file = FileUtil.getFile(this, uri);
RequestBody mFile = RequestBody.create(MediaType.parse("image/*"), file);
MultipartBody.Part fileToUpload = MultipartBody.Part.createFormData("file", file.getName(), mFile);
RequestBody filename = RequestBody.create(MediaType.parse("text/plain"), file.getName());
ApiConfig apiConfig = retrofit.create(ApiConfig.class);
Call<ResponseBody> addNews = apiConfig.uploadImage(fileToUpload,
filename,
etArabicTitle.getText().toString(),
etEnglishTitle.getText().toString(),
etRussianTitle.getText().toString(),
etItalianTitle.getText().toString(),
etArabicDescription.getText().toString(),
etEnglishDescription.getText().toString(),
etRussianDescription.getText().toString(),
etItalianDescription.getText().toString());
addNews.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Toast.makeText(News.this, "success" + "\n" + response.message(), Toast.LENGTH_SHORT).show();
Intent intent = new Intent(News.this,Menu.class);
startActivity(intent);
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Toast.makeText(News.this, "fail" + t.getMessage(), Toast.LENGTH_SHORT).show();
t.printStackTrace();
}
});
}
When using multipart requests using Retrofit, you can pass extra parameters using #Part annotation having RequestBody fields for additional parameters.
So, You can pass it as RequestBody type for all parameters except multipart body like below :
#Multipart
#POST("/androidfiles/insertNews.php")
Call<ResponseBody> uploadImage(#Part MultipartBody.Part file,
#Part("name") RequestBody name,
#Part("tArabic") RequestBody arabicTitle,
#Part("tEnglish") RequestBody englishTitle,
#Part("tRussian") RequestBody russianTitle,
#Part("tItalian") RequestBody italianTitle,
#Part("dArabic") RequestBody arabicDescription,
#Part("dEnglish") RequestBody englishDescription,
#Part("dRussian") RequestBody russianDescription,
#Part("dItalian") RequestBody italianDescription);
Now, for calling such API; you'll need to pass it by creating RequestBody for additional parameters as MIME Type text/plain using syntax (i.e. RequestBody.create(MediaType.parse("text/plain"), your variable goes here))
During API build up, you can pass call it as:
Call<ResponseBody> addNews = apiConfig.uploadImage(fileToUpload,
filename,
RequestBody.create(MediaType.parse("text/plain"), etArabicTitle.getText().toString()), //This will make it as RequestBody to pass it along image/files.
RequestBody.create(MediaType.parse("text/plain"), etEnglishTitle.getText().toString()),
RequestBody.create(MediaType.parse("text/plain"), etRussianTitle.getText().toString()),
RequestBody.create(MediaType.parse("text/plain"), etItalianTitle.getText().toString()),
RequestBody.create(MediaType.parse("text/plain"), etArabicDescription.getText().toString()),
RequestBody.create(MediaType.parse("text/plain"), etEnglishDescription.getText().toString()),
RequestBody.create(MediaType.parse("text/plain"), etRussianDescription.getText().toString()),
RequestBody.create(MediaType.parse("text/plain"), etItalianDescription.getText().toString()));
try changing #Field to #Part . like this :
#Multipart
#POST("/androidfiles/insertNews.php")
Call<ResponseBody> uploadImage(#Part MultipartBody.Part file, #Part("name") RequestBody name,
#Part("tArabic") String arabicTitle,
#Part("tEnglish") String englishTitle,
#Part("tRussian") String russianTitle,
#Part("tItalian") String italianTitle,
#Part("dArabic") String arabicDescription,
#Part("dEnglish") String englishDescription,
#Part("dRussian") String russianDescription,
#Part("dItalian") String italianDescription);
I'm trying to upload an image to the server using Retrofit2, but am very unsure on how to do so.
The documentation left me a bit confused and I have tried the solution mentioned here, but it did not work for me.
Here is the code snippet I'm currently using, which doesn't send anything to the server:
// Service
#Multipart
#POST("0.1/gallery/{galleryId}/addImage/")
Call<ResponseBody> addImage(#Path("galleryId") String galleryId, #Part MultipartBody.Part image);
//Call
MultipartBody.Part imagePart = MultipartBody.Part.createFormData("image", file.getName(), RequestBody.create(MediaType.parse("image/*"), file));
Call<ResponseBody> call = service. addImage("1234567890", imagePart);
However, I'm able to do it just fine using Retrofit 1.9 with a TypedFile.
Am I doing something wrong or Retrofit2 has some issue with this sort of thing?
I've struggled for a while with this to, I ended up with this solution to finally make it work... Hopes it helps:
Map<String, RequestBody> map = new HashMap<>();
map.put("Id",Utils.toRequestBody("0"));
map.put("Name",Utils.toRequestBody("example"));
String types = path.substring((path.length() - 3), (path.length()));
File file = new File(pathOfYourFile);
RequestBody fileBody = RequestBody.create(MediaType.parse("image/jpg"), file);
map.put("file\"; filename=\"cobalt." + types + "\"", fileBody);
Call<ResponseBody> call = greenServices.upload(map);
In the greenServices interface:
#Multipart
#POST(Constants.URL_UPLOAD)
Observable<Response<ResponseBody>> uploadNew(#PartMap Map<String, RequestBody> params);
hi please check how we can send image in retrofit2.In form of part you need to send image and other data as well.
public interface ApiInterface {
#Multipart
#POST("0.1/gallery/{galleryId}/addImage/")
Call<User> checkapi (#Part("file\"; filename=\"pp.png\" ") RequestBody file , #Part("FirstName") RequestBody fname, #Part("Id") RequestBody id);
}
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();
}
});
Thanks hope this will help you.
I have to upload image and also send String data in post method using Retrofit 2. I'm using the flowing method to do that.
#Multipart
#FormUrlEncoded
#POST("signup/step3")
Call<BasicModel> completeRegistration(
/*All Basic Parameter*/
#Field("mobile_no") String mobileNo,
/*For User Image*/
#Part MultipartBody.Part photoFile
);
But I'm getting the following error.
java.lang.IllegalArgumentException: Only one encoding annotation is allowed.
for method AllNetworkCalls.completeRegistration
at retrofit2.ServiceMethod$Builder.methodError(ServiceMethod.java:695)
at retrofit2.ServiceMethod$Builder.methodError(ServiceMethod.java:686)
at retrofit2.ServiceMethod$Builder.parseMethodAnnotation(ServiceMethod.java:266)
at retrofit2.ServiceMethod$Builder.build(ServiceMethod.java:169)
at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:166)
at retrofit2.Retrofit$1.invoke(Retrofit.java:145)
at java.lang.reflect.Proxy.invoke(Proxy.java:397)
at $Proxy1.completeRegistration(Unknown Source)
at com.sslwireless.app.Activities.SignUp.RegistrationActivity_5.completeRegistration(RegistrationActivity_5.java:244)
at com.sslwireless.app.Activities.SignUp.RegistrationActivity_5.access$1100(RegistrationActivity_5.java:51)
at com.sslwireless.app.Activities.SignUp.RegistrationActivity_5$5.onClick(RegistrationActivity_5.java:132)
at android.view.View.performClick(View.java:4856)
at android.view.View$PerformClick.run(View.java:19956)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:211)
at android.app.ActivityThread.main(ActivityThread.java:5389)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1020)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:815)
Is there any other way I can do that ?
Using Retrofit 2, you need to use either OkHttp’s RequestBody or MultipartBody.Part classes and encapsulate your file into a request body. Let’s have a look at the interface definition for file uploads.
public interface FileUploadService {
#Multipart
#POST("upload")
Call<ResponseBody> upload(#Part("description") RequestBody description,
#Part MultipartBody.Part file);
}
in Java file
private void uploadFile(Uri fileUri) {
// create upload service client
FileUploadService service =
ServiceGenerator.createService(FileUploadService.class);
// https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java
// use the FileUtils to get the actual file by uri
File file = FileUtils.getFile(this, fileUri);
// 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);
// add another part within the multipart request
String descriptionString = "hello, this is description speaking";
RequestBody description =
RequestBody.create(
MediaType.parse("multipart/form-data"), descriptionString);
// finally, execute the request
Call<ResponseBody> call = service.upload(description, body);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call,
Response<ResponseBody> response) {
Log.v("Upload", "success");
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.e("Upload error:", t.getMessage());
}
});
}
I used to send POST request to server with Retrofit2:
#POST("goals")
Call<Void> postGoal(#Body Goal goal);
where Goal was object with some String/Integer fields.
Now I need to add a photo file there.
I know I need to switch to use Multipart:
#Multipart
#POST("goals")
Call<Void> postGoal(
#Part("picture") RequestBody picture
);
//...
//Instantaining picture
RequestBody.create(MediaType.parse("image/*"), path)
But how am I supposed to add previous fields ? In particular is there a way to add whole Goal object without dividing it for fields ?
for sending json and file you can follow something like this.
#Multipart
#POST("goals")
Call<JsonModel> postGoal(#Part MultipartBody.Part file, #Part("json") RequestBody json);
Now convert your Object which you want to send as a json into json using Gson.
like this.
String json = new Gson().toJson(new Goal());
File file = new File(path);
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);
// add another part within the multipart request
RequestBody jsonBody=
RequestBody.create(
MediaType.parse("multipart/form-data"), json);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build();
RestApi api = retrofit.create(RestApi.class);
Call<ResponseBody> call = api.upload(jsonBody, body);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Log.d("onResponse: ", "success");
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d("onFailure: ", t.getLocalizedMessage());
}
});
You can add #Part with you goal like this
#Multipart
#POST("goals")
Call<Void> postGoal(
#Part("picture") RequestBody picture,
#Part("goal") RequestBody goal
);
//...
//Instantaining picture
RequestBody.create(MediaType.parse("image/*"), path)
You can find more details : retrofit-2-how-to-upload-files-to-server