I'm using Retrofit v.2.2.0 to upload a picture to my server but the server returns a null value stating no image has been uploaded. The logs shows the image is uploaded and the file name is correct when uploaded. What can be the problem yet it works in postman?
UploadProfilePicture.java
public class UploadProfilePicture extends ContextWrapper {
private GetOnUpload onUpload;
private File imageFile,filesDir,file;
private Uri fileUri;
private String profilePic = "profile_pic";
private String fileName;
private ParcelFileDescriptor parcelFileDescriptor;
private FileDescriptor fileDescriptor;
private Bitmap profileImage;
private OutputStream os;
private OkHttpLogClientAPI okHttpLogClientAPI;
private GetOnUpload mInterfaceService;
public UploadProfilePicture(Context base) {
super(base);
okHttpLogClientAPI = new OkHttpLogClientAPI(getBaseContext());
mInterfaceService = okHttpLogClientAPI.logger().create(GetOnUpload.class);
}
public void uploadPic(Uri fileUri,String fileName, final OnSetUploadProfilePic setOnUpload) {
//Build Req estBodies for the map object and a MultipartBody.Part to encapsulate the prof_pic_drawer
this.fileUri = fileUri;
this.fileName = fileName;
try {
getBitmapFromUri();
} catch (IOException e) {
e.printStackTrace();
}
file = persistImage();
RequestBody finalRequestBody = builder.build();
RequestBody requestFile =
RequestBody.create(MediaType.parse("multipart/form-data"), getBytesFromBitmap(profileImage));
// MultipartBody.Part is used to send also the actual file name
MultipartBody.Part body =
MultipartBody.Part.createFormData("file", "avatar.jpg", requestFile);
Call<ResponseUserModel> call = mInterfaceService.upload(body);
call.enqueue(new Callback<ResponseUserModel>() {
@Override
public void onResponse(Call<Response> call, Response<Response> response) {
if (response.isSuccessful()) {
setOnUpload.uploadMessage(response.body());
} else {
Toast.makeText(getBaseContext(), getString(R.string.failed_to_upload), Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<Response> call, Throwable t) {
Toast.makeText(getBaseContext(), getString(R.string.failed_to_upload), Toast.LENGTH_SHORT).show();
}
});
}
}
public static byte[] getBytesFromBitmap(Bitmap bitmap) {
if (bitmap!=null) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 70, stream);
return stream.toByteArray();
}
return null;
}
private MultipartBody.Part prepareFilePart() {
//TODO: Use FileUtils to get the actual file by uri
try {
getBitmapFromUri();
file = persistImage();
} catch (IOException e) {
e.printStackTrace();
}
try {
RequestBody requestFile = RequestBody.create(
MediaType.parse(getBaseContext().getContentResolver().getType(fileUri)), file);
return MultipartBody.Part.createFormData("file", file.getName(), requestFile);
} catch (NullPointerException e) {
Toast.makeText(getBaseContext(), "" + e.getMessage(), Toast.LENGTH_SHORT).show();
return null;
}
}
private RequestBody createPartFromString(String descriptionString) {
return RequestBody.create(MultipartBody.FORM, descriptionString);
}
private void getBitmapFromUri() throws IOException {
profileImage = MediaStore.Images.Media.getBitmap(this.getContentResolver(), fileUri);
}
private File persistImage() {
filesDir = getFilesDir();
imageFile = new File(filesDir, fileName + ".jpg");
OutputStream os;
try {
os = new FileOutputStream(imageFile);
profileImage.compress(Bitmap.CompressFormat.JPEG, 70, os);
os.flush();
os.close();
} catch (Exception e) {
Log.e(getClass().getSimpleName(), "Error writing bitmap", e);
}
return imageFile;
}}
GetOnUpload.java
public interface GetOnUpload {
@Multipart
@POST(Constants.UPLOAD_URL)
Call<Response> upload(@Part MultipartBody.Part file);}
Log
http://local.com/api/v1/avatar http/1.1
11-14 18:40:02.742 8851-9593/com.local.test D/OkHttp: Content-Type: multipart/form-data; boundary=d43da080-f2c3-4743-8cfd-9526cc0bd2f7
11-14 18:40:02.742 8851-9593/com.local.test D/OkHttp: Content-Length: 12424
11-14 18:40:02.743 8851-9593/com.local.test D/OkHttp: --d43da080-f2c3-4743-8cfd-9526cc0bd2f7
11-14 18:40:02.743 8851-9593/com.local.test D/OkHttp: Content-Disposition: form-data; name="file"; filename="avatar.jpg"
11-14 18:40:02.743 8851-9593/com.local.test D/OkHttp: Content-Type: multipart/form-data
11-14 18:40:02.743 8851-9593/com.local.test D/OkHttp: Content-Length: 12201
11-14 18:40:02.743 8851-9593/com.local.test D/OkHttp:
11-14 18:40:02.744 8851-9593/com.local.test D/OkHttp: --d43da080-f2c3-4743-8cfd-9526cc0bd2f7--
11-14 18:40:02.744 8851-9593/com.local.test D/OkHttp: --> END POST (12424-byte body)
11-14 18:40:03.332 8851-9593/com.local.test D/OkHttp: <-- 200 OK http://local.com/api/v1/avatar (587ms)
11-14 18:40:03.332 8851-9593/com.local.test D/OkHttp: Server: nginx/1.10.3 (Ubuntu)
11-14 18:40:03.332 8851-9593/com.local.test D/OkHttp: Content-Type: application/json
11-14 18:40:03.332 8851-9593/com.local.test D/OkHttp: Transfer-Encoding: chunked
11-14 18:40:03.332 8851-9593/com.local.test D/OkHttp: Connection: keep-alive
11-14 18:40:03.332 8851-9593/com.local.test D/OkHttp: Cache-Control: no-cache, private
11-14 18:40:03.332 8851-9593/com.local.test D/OkHttp: Date: Tue, 14 Nov 2017 15:40:03 GMT
11-14 18:40:03.332 8851-9593/com.local.test D/OkHttp: X-RateLimit-Limit: 60
11-14 18:40:03.332 8851-9593/com.local.test D/OkHttp: X-RateLimit-Remaining: 59
11-14 18:40:03.333 8851-9593/com.local.test D/OkHttp: {"user":"Failed","status":"Image file not uploaded"}
This example worked for me
//My data manager
public void doUpload(
Context context,
String url) {
Uri uri = Uri.parse(url);
File file = new File(getPath(context, uri));
RequestBody reqFile = RequestBody.create(MediaType.parse("image/*"), file);
MultipartBody.Part body = MultipartBody.Part.createFormData("imageParameterName", file.getName(), reqFile);
uploadService(body)
}
//REST service
@Multipart
@POST("upload.aspx")
Call<DefaultDTO> uploadService(@Part MultipartBody.Part image);
It seems there is a problem with OKHttp so when posting a file and data to the server with retrofit use this format
file = new File(fileUri.getPath());
RequestBody fileBody = RequestBody.create(MediaType.parse("image/*"),file);
RequestBody dataBody = RequestBody.create(MediaType.parse("text/plain"), "id");
Call<Response> call = mInterfaceService.upload(fileBody,dataBody);
call.enqueue(new Callback<Response>() {
@Override
public void onResponse(Call<Response> call, Response<Response> response) {
if (response.isSuccessful()) {
setOnUpload.uploadMessage(response.body());
if(file.exists())
file.delete();
} else {
Toast.makeText(getBaseContext(), getString(R.string.failed_to_upload), Toast.LENGTH_SHORT).show();
}
}
public interface GetOnUpload {
@Multipart
@POST(Constants.UPLOAD_URL)
Call<Response> upload(@Part("file\";filename=\"avatar.jpg\" ") RequestBody file,@Part("id")RequestBody user);
}
ImageFilePath
@SuppressLint("NewApi")
@TargetApi(Build.VERSION_CODES.KITKAT)
public class ImageFilePath {
/**
* Method for return file path of Gallery image
*
* @param context
* @param uri
* @return path of the selected image file from gallery
*/
static String nopath = "Select Video Only";
@TargetApi(Build.VERSION_CODES.KITKAT)
@SuppressLint("NewApi")
public static String getPath(final Context context, final Uri uri) {
// check here to KITKAT or new version
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/"
+ split[1];
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"),
Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[] { split[1] };
return getDataColumn(context, contentUri, selection,
selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return nopath;
}
/**
* Get the value of the data column for this Uri. This is <span id="IL_AD2"
* class="IL_AD">useful</span> for MediaStore Uris, and other file-based
* ContentProviders.
*
* @param context
* The context.
* @param uri
* The Uri to query.
* @param selection
* (Optional) Filter used in the query.
* @param selectionArgs
* (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
public static String getDataColumn(Context context, Uri uri,
String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = { column };
try {
cursor = context.getContentResolver().query(uri, projection,
selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
} finally {
if (cursor != null)
cursor.close();
}
return nopath;
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri
.getAuthority());
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri
.getAuthority());
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri
.getAuthority());
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri
.getAuthority());
}
}
ChooseImg
private void openChooseImgDialog() {
Intent getIntent = new Intent(Intent.ACTION_GET_CONTENT);
getIntent.setType("image/*");
Intent pickIntent = new Intent(Intent.ACTION_PICK, 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, PICK_IMAGE);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case PICK_IMAGE:
if (resultCode == Activity.RESULT_OK) {
uri = data.getData();
File_Path = ImageFilePath.getPath(getActivity(), data.getData());
// File_Path = RealPathUtil.getRealPathFromURI_API19(getActivity(), data.getData());
// String filename = uri.getLastPathSegment();
Log.d("displayfiletypes","**** "+data.getData() + " "+File_Path);
tv_feedbackfilename.setText(File_Path.substring(File_Path.lastIndexOf("/")+1));
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver(), uri);
// Log.d(TAG, String.valueOf(bitmap));
// mImgView.setImageBitmap(bitmap);
} catch (IOException e) {
e.printStackTrace();
}
} else {
Toast.makeText(getActivity(), "Something Went Wrong", Toast.LENGTH_SHORT).show();
}
break;
}
}
Interface
@Multipart
@POST("url")
Call<ResponseBody> add_feedback(@Part MultipartBody.Part file);
Add this code in your Activity
Retrofit adapter = new Retrofit.Builder()
.baseUrl(Constandapi.ROOT_URL)
.build();
RequestBody requestBody = RequestBody.create(MediaType.parse("*/*"), file);
MultipartBody.Part fileToUpload = MultipartBody.Part.createFormData("your php file key", file.getName(), requestBody);
Call<ResponseBody> adding_feedback = addfeedback.add_feedback(auth_key_sent, subjectstring_sent, feedbackmsg_sent, fileToUpload);
adding_feedback.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful())
{
progressDialog.dismiss();
String result = null;
try{
result = response.body().string();
Log.d("createddates","responce"+result);
}catch (IOException e){
e.printStackTrace();
}catch (JSONException jsone){
jsone.printStackTrace();
}
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Toast.makeText(getActivity(), "Please try after sometime", Toast.LENGTH_SHORT).show();
Log.d("printmessages","*** "+call.toString() + " "+t.toString());
progressDialog.dismiss();
}
});