I am trying to upload an image to our project's server using Retrofit 2
The image is picked through an image picking activity and seems to work since the file (image) can be displayed using Picasso.
Retrofit succeeds however the server doesn't seem to get the file.
Here is the server side part.
func (c *gin.Context) {
file, header , err := c.Request.FormFile("profileImage")
// err = http: no such file
}
Sever side error message
Even the RequestBody prints coherent information when I tested it (size, image type...)
Service :
#Multipart
#PATCH("/user/profileImage")
Call<ResponseBody> modifyUserImage(#Part("profileImage") RequestBody profileImage, #Part("userID") RequestBody userID);
Following code is part of the same Fragment class
Opening image picking activity :
Intent getIntent = new Intent(Intent.ACTION_GET_CONTENT);
getIntent.setType("image/*");
Intent pickIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
pickIntent.setType("image/*");
Intent chooserIntent = Intent.createChooser(getIntent, "Select Image");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[]{pickIntent});
startActivityForResult(chooserIntent, 1);
On Activity Result:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK && requestCode == 1) {
// process the result
Uri selectedImage = data.getData();
String wholeID = DocumentsContract.getDocumentId(selectedImage);
String id = wholeID.split(":")[1];
String[] column = {MediaStore.Images.Media.DATA};
String sel = MediaStore.Images.Media._ID + "=?";
Cursor cursor = getActivity().getContentResolver().
query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
column, sel, new String[]{id}, null);
String filePath = "";
int columnIndex = cursor.getColumnIndex(column[0]);
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex);
}
cursor.close();
file = new File(filePath);
Picasso
.with(getActivity().getApplicationContext())
.load(file)
.into(civ_userProfilePicture);
}
}
Request :
Call<ResponseBody> call = ServiceSingelton.getmInstance().getService()
.modifyUserImage(RequestBody.create(MediaType.parse("image/*"), file),
RequestBody.create(MediaType.parse("text/plain"), ServiceSingelton.getmInstance().getUserID()));
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.code() == 200) {
Log.d("RETROFIT SUCCESS", "Pic should be sent");
} else {
Log.d("RETROFIT SUCCESS", "Error code received modifying user");
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d("RETROFIT ERROR", t.getMessage());
}
});
Someone gave me this fix which worked :
To post a part with filename, you should change #Part("profileImage")
RequestBody profileImage to #Part RequestBody profileImage, and pass
it MultipartBody.Part.createFormData(partName, filename, requestBody):
// Service
#Multipart
#PATCH("/user/profileImage")
Call<ResponseBody> modifyUserImage(#Part MultipartBody.Part profileImage, #Part("userID") RequestBody userID);
// Call
MultipartBody.Part imagePart = MultipartBody.Part.createFormData("profileImage", file.getName(), RequestBody.create(MediaType.parse("image/*"), file));
Call<ResponseBody> call = ServiceSingelton.getmInstance().getService()
.modifyUserImage(imagePart,
RequestBody.create(MediaType.parse("text/plain"), ServiceSingelton.getmInstance().getUserID()));
Related
I am getting Error when i used to push data and the error i am getting is:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.oakridgebs.dealsinmall, PID: 3414
java.lang.IllegalArgumentException: Only one encoding annotation is allowed.
for method ClickAndPostApi.clicPost
at retrofit2.Utils.methodError(Utils.java:52)
at retrofit2.Utils.methodError(Utils.java:42)
at retrofit2.RequestFactory$Builder.parseMethodAnnotation(RequestFactory.java:227)
at retrofit2.RequestFactory$Builder.build(RequestFactory.java:161)
at retrofit2.RequestFactory.parseAnnotations(RequestFactory.java:65)
at retrofit2.ServiceMethod.parseAnnotations(ServiceMethod.java:25)
at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:168)
at retrofit2.Retrofit$1.invoke(Retrofit.java:147)
at java.lang.reflect.Proxy.invoke(Proxy.java:913)
at $Proxy9.clicPost(Unknown Source)
at com.oakridgebs.dealsinmall.ClickAndPostActivity$1.onClick(ClickAndPostActivity.java:134)
at android.view.View.performClick(View.java:6392)
at android.view.View$PerformClick.run(View.java:25121)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:197)
at android.app.ActivityThread.main(ActivityThread.java:7022)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:515)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:837)
Here is my Interface
#Multipart
#FormUrlEncoded
#POST("click_and_posts")
Call<ResponseBody> clicPost(
#Header("Token") String token, // if there is headers
#Part MultipartBody.Part file,
#Field("click_and_post[category_id]") String category_id,
#Field("click_and_post[brand_id]") String brand_id,
#Field("click_and_post[location]") String location
);
I am capturing the image and taking the uri as shown below on Activity Result
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 7 && resultCode == RESULT_OK && data != null && data.getData() != null) {
photoUri = data.getData();
try {
// Adding captured image in bitmap.
bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), photoUri);
// adding captured image in imageview.
capturedImage.setImageBitmap(bitmap);
} catch (IOException e) {
e.printStackTrace();
}
}
}
IN this i am taking photouri and i am passing as shown below
My Code is
File originalFile = FileUtils.getFile(getApplicationContext(), photoUri);
RequestBody filePart = RequestBody.create(MediaType.parse(getContentResolver().getType(photoUri)),
originalFile);
MultipartBody.Part file = MultipartBody.Part.createFormData("click_and_post[image]", originalFile.getName(), filePart);
Call<ResponseBody> call = LoginSignupClients.getInstance().getApiClickandPost().clicPost(token, file, category_id, brand_id, location );
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.code() == 200){
Toast.makeText(ClickAndPostActivity.this, "You Posted the Deal Sucessfully", Toast.LENGTH_LONG).show();
Intent intent = new Intent(ClickAndPostActivity.this, DashboardActivity.class);
startActivity(intent);
finish();
}else {
Toast.makeText(ClickAndPostActivity.this, "Unable to post Your Data", Toast.LENGTH_LONG).show();
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Toast.makeText(ClickAndPostActivity.this, t.getMessage(), Toast.LENGTH_LONG).show();
}
});
Or else is there any way to pass the bitmap. Can u help me please
in the error described it can only use one encoding annotation, so try removing the following annotation:
#FormUrlEncoded
in your interface
I'm using spring for a backend and retrofit for rest client.
I want to upload a file
backend code
#PostMapping("/upload")
public ResponseEntity<String> handleFileUpload(#RequestParam("file") MultipartFile file, Model model) {
String name = null;
try {
storageService.store(file);
model.addAttribute("message", "You successfully uploaded " + file.getOriginalFilename() + "!");
files.add(file.getOriginalFilename());
name = files.get(files.size()-1).toString();
System.err.println(name.toString());
} catch (Exception e) {
model.addAttribute("message", "FAIL to upload " + file.getOriginalFilename() + "!");
}
return new ResponseEntity<String>(file.getOriginalFilename() , HttpStatus.OK);
}
function store
public void store(MultipartFile file) {
try {
Files.copy(file.getInputStream(), this.rootLocation.resolve(file.getOriginalFilename()));
} catch (Exception e) {
throw new RuntimeException("FAIL!");
}
}
android code to select and upload file
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Bitmap bitmap = ImagePicker.getImageFromResult(getActivity(), requestCode, resultCode, data);
if (bitmap != null) {
image.setImageBitmap(bitmap);
selection=data.getData();
String[] filepath={MediaStore.Images.Media.DATA};
Cursor cursor=getActivity().getContentResolver().query(selection,filepath,null,null,null);
cursor.moveToFirst();
int column=cursor.getColumnIndex(filepath[0]);
String path=cursor.getString(column);
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);
upload(body);
}
upload function
public void upload(MultipartBody.Part path){
Call<ResponseBody> callUploader = iBackEndService.uploadAttachment(path);
callUploader.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Log.d(TAG,"UPLODER REUSSI" +" "+response.message());
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable throwable) {
Log.e(TAG,throwable.getMessage());
}
});
}
Retrofit mapping (I'm using Retrofit 2.1.0)
#Multipart
#POST("upload")
Call<ResponseBody> uploadAttachment(#Part MultipartBody.Part filePart);
my upload function jump to onResponse but the file was not upload
I have implemented a retrofit client side implementation of uploading an image to a server using #MultipartBody but am unable to handle the upload on the server side:
This is my client side implementation (just to make sure I'm doing it right):
/**
* Activity
*/
#OnClick(R.id.change_profile_image_button)
public void addProfileImage() {
Intent pickIntent = new Intent();
pickIntent.setType("image/*");
pickIntent.setAction(Intent.ACTION_GET_CONTENT);
Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
String pickTitle = "Take or select a photo";
Intent chooserIntent = Intent.createChooser(pickIntent, pickTitle);
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] { takePhotoIntent });
startActivityForResult(chooserIntent, REQUEST_CODE_PICTURE);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
if (data.getData() == null) {
Toast.makeText(getActivity(),
"Image file could not be uploaded",
Toast.LENGTH_SHORT).show();
return;
}
mProfileImageFile = getFileFromUri(data.getData());
mProfilePresenter.uploadProfileImage(mProfileImageFile);
}
}
private File getFileFromUri(Uri fileUri) {
if (fileUri != null) {
String filePath = fileUri.getPath();
if (filePath != null) {
return new File(filePath);
}
}
return null;
}
/**
* UserRepository
*/
#Override
public void uploadProfileImage(File file) {
RequestBody reqFile = RequestBody.create(MediaType.parse("image/*"), file);
MultipartBody.Part body = MultipartBody.Part.createFormData("upload", file.getName(), reqFile);
RequestBody name = RequestBody.create(MediaType.parse("text/plain"), "upload");
Call<ResponseBody> req = userServiceApi.uploadProfileImage(body, name);
req.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(#NonNull Call<ResponseBody> call,
#NonNull Response<ResponseBody> response) {
// Do Something
if (response.isSuccessful()) {
//String location = response.body();
//eventBus.post(new SuccessUploadProfileImageEvent(location));
Log.d(TAG, "Successfully uploaded image");
} else {
eventBus.post(new FailUploadProfileImageEvent());
}
}
#Override
public void onFailure(#NonNull Call<ResponseBody> call, #NonNull Throwable t) {
t.printStackTrace();
}
});
}
/**
* UserService
*/
#Multipart
#POST("users/upload-profile-image/")
Call<ResponseBody> uploadProfileImage(#Part MultipartBody.Part image,
#Part("name") RequestBody name);
On the server side I have tried to implement this view but it doesn't work:
class UserProfileUploadImageView(RetrieveModelMixin, UpdateModelMixin, generics.GenericAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = (IsAuthenticated,)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
#detail_route(methods=['POST'], permission_classes=[IsAuthenticated])
#parser_classes((FormParser, MultiPartParser,))
def image(self, request, *args, **kwargs):
if 'upload' in request.data:
user_profile = self.get_object()
user_profile.image.delete()
upload = request.data['upload']
user_profile.image.save(upload.name, upload)
return Response(status=HTTP_201_CREATED, body={'url': user_profile.image.url})
else:
return Response(status=HTTP_400_BAD_REQUEST)
And in the User model:
profile_image = models.ImageField(blank=True, null=True, upload_to="profile_image")
I have a function to request upload image with Retrofit like this
void uploadPhoto(File file) {
RequestBody photo = RequestBody.create(MediaType.parse("application/image"), file);
RequestBody body = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addFormDataPart("photo", file.getName(), photo)
.build();
fragment.showProgressDialog(fragment.loading);
fragment.getApi().uploadPhoto(PrefHelper.getString(PrefKey.TOKEN), body)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Observer<GenericResponse>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
fragment.dismissProgressDialog();
Timber.e(e.getMessage());
}
#Override
public void onNext(GenericResponse response) {
fragment.dismissProgressDialog();
if (response.getCode() == 1) {
fragment.showSuccessDialog("Saving success", false);
userInfo();
}
}
});
}
and for the example, I have a button to upload image in my fragment
#OnClick(R.id.btnChangePicture)
void onChangePictureClicked() {
}
What code should i put in
OnChangePictureClicked
So i can choose an image from gallery and then I request it to API.
void uploadPhoto(File file)
Thanks
Transform your image to an array of bytes and then create an Object Dto like the example below and send it to the server through Retrofit.
#Data
public class SetProfileImageRequestDto {
#SerializedName("Token")
private String token;
#SerializedName("Stream")
private byte[] image;
}
Retrofit Api Service:
#POST("SetProfileImage/")
Observable<ResultResponseDto> setProfileImage(#Body SetProfileImageRequestDto profileImageRequestDto);
Hope it works.
Create a Uri object in Activity or fragment.
private Uri selectedImage;
After that, You will get gallery result in onActivityResult.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && null != data) {
selectedImage = data.getData();
}
}
Then in your onChangePictureClicked method.
#OnClick(R.id.btnChangePicture)
void onChangePictureClicked() {
if(selectedImage !=null){
uploadPhoto(new File(selectedImage.getPath()));
}
}
You can use multipart with retrofit please look this example of image upload using retrofit, its best for you.
its working for me.
//Create Upload Server Client
ApiService service = RetroClient.getApiService();
//File creating from selected URL
File file = new File(imagePath);
// create RequestBody instance from file
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
MultipartBody.Part body =
MultipartBody.Part.createFormData("uploaded_file", file.getName(), requestFile);
Call<Result> resultCall = service.uploadImage(body);
resultCall.enqueue(new Callback<Result>() {
#Override
public void onResponse(Call<Result> call, Response<Result> response) {
progressDialog.dismiss();
// Response Success or Fail
if (response.isSuccessful()) {
if (response.body().getResult().equals("success"))
Snackbar.make(parentView, R.string.string_upload_success, Snackbar.LENGTH_LONG).show();
else
Snackbar.make(parentView, R.string.string_upload_fail, Snackbar.LENGTH_LONG).show();
} else {
Snackbar.make(parentView, R.string.string_upload_fail, Snackbar.LENGTH_LONG).show();
}
/**
* Update Views
*/
imagePath = "";
textView.setVisibility(View.VISIBLE);
imageView.setVisibility(View.INVISIBLE);
}
#Override
public void onFailure(Call<Result> call, Throwable t) {
progressDialog.dismiss();
}
});
http://www.pratikbutani.com/2016/06/android-upload-image-file-using-retrofit-2-0/
I tried the following but on response i am getting 500 error (Internal Server Error) -- help me design the interface for the request in the above screenshot...thanks
#Multipart
#POST("myrecord")
Call<ResponseBody> addRecord(#Query("token") String token,#Query("userid") int userId,
#Query("name") String name, #Part("file") RequestBody file);
File file = new File(getRealPathFromURI(data.getData()));
RequestBody requestFile = RequestBody.create(MediaType.parse("image/*"), getRealPathFromURI(data.getData()));`
Call<ResponseBody> responseBodyCall = service.addRecord(token, userId,
"newFileName", requestFile);
responseBodyCall.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Log.d("Response", "="+response.code());
Log.d("Response", "= "+response.message());
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d("failure", "message = " + t.getMessage());
Log.d("failure", "cause = " + t.getCause());
}
});`
The following code worked :)
#Multipart
#POST("myrecord")
Call<ResponseBody> addRecord(#Query("token") String token, #Query("userid") int userId,
#Query("name") String name, #Part MultipartBody.Part file);
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if ((requestCode == FILE_SELECT_CODE) && (resultCode == -1)) {
File file = new File(getRealPathFromURI(data.getData()));
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), getRealPathFromURI(data.getData()));
MultipartBody.Part multipartBody =MultipartBody.Part.createFormData("file",file.getName(),requestFile);
Call<ResponseBody> responseBodyCall = service.addRecord(token, userId, "fileName", multipartBody);
responseBodyCall.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Log.d("Success", "success "+response.code());
Log.d("Success", "success "+response.message());
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d("failure", "message = " + t.getMessage());
Log.d("failure", "cause = " + t.getCause());
}
});
}
}
#Multipart
#POST("myrecord")
Call<ResponseBody> addRecord(#Part("file") RequestBody file,#Part MultipartBody.Part file,
#Query("token") String token,#Query("userid") int userId,#Query("name") String name);
RequestBody requestFile =
RequestBody.create(MediaType.parse("multipart/form-data"), file);
MultipartBody.Part body =
MultipartBody.Part.createFormData("picture", file.getName(), requestFile);
String descriptionString = "your description";
RequestBody description =
RequestBody.create(
MediaType.parse("multipart/form-data"), descriptionString);
for more information look into this link:
https://futurestud.io/blog/retrofit-2-how-to-upload-files-to-server
If you would like to send file as binary in a body without using multipart you can remove #Multipart annotation from your code and use #Body annotation. It looks like
#POST("myrecord")
Call<ResponseBody> addRecord(#Query("token") String token,#Query("userid") int userId,
#Query("name") String name, #Body RequestBody file);
File file = new File(getRealPathFromURI(data.getData()));
RequestBody requestFile = RequestBody.create(MediaType.parse("image/*"), getRealPathFromURI(data.getData()));
Call<ResponseBody> responseBodyCall = service.addRecord(token, userId,
"newFileName", requestFile);
responseBodyCall.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Log.d("Response", "="+response.code());
Log.d("Response", "= "+response.message());
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d("failure", "message = " + t.getMessage());
Log.d("failure", "cause = " + t.getCause());
}
});`
public String getRealPathFromURI(Context context, Uri contentUri) {
Log.d("imin", "onClick: in image conversion");
Cursor cursor = null;
try {
String[] proj = {MediaStore.Images.Media.DATA};
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
Log.d("imin", "onClick: in image conversion try");
return cursor.getString(column_index);
} finally {
Log.d("imin", "onClick: in image conversion finally");
if (cursor != null) {
cursor.close();
}
}
}