POST Multipart Form Data using Retrofit 2.0 including image
There is a correct way of uploading a file with its name with Retrofit 2, without any hack:
Define API interface:
@Multipart@POST("uploadAttachment")Call<MyResponse> uploadAttachment(@Part MultipartBody.Part filePart); // You can add other parameters too
Upload file like this:
File file = // initialize file hereMultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(), RequestBody.create(MediaType.parse("image/*"), file));Call<MyResponse> call = api.uploadAttachment(filePart);
This demonstrates only file uploading, you can also add other parameters in the same method with @Part
annotation.
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(); }});
I used Retrofit 2.0 for my register users, send multipart/form File image and text from register account
In my RegisterActivity, use an AsyncTask
//AsyncTaskprivate class Register extends AsyncTask<String, Void, String> { @Override protected void onPreExecute() {..} @Override protected String doInBackground(String... params) { new com.tequilasoft.mesasderegalos.dbo.Register().register(txtNombres, selectedImagePath, txtEmail, txtPassword); responseMensaje = StaticValues.mensaje ; mensajeCodigo = StaticValues.mensajeCodigo; return String.valueOf(StaticValues.code); } @Override protected void onPostExecute(String codeResult) {..}
And in my Register.java class is where use Retrofit with synchronous call
import android.util.Log;import com.tequilasoft.mesasderegalos.interfaces.RegisterService;import com.tequilasoft.mesasderegalos.utils.StaticValues;import com.tequilasoft.mesasderegalos.utils.Utilities;import java.io.File;import okhttp3.MediaType;import okhttp3.MultipartBody;import okhttp3.RequestBody;import okhttp3.ResponseBody;import retrofit2.Call; import retrofit2.Response;/**Created by sam on 2/09/16.*/public class Register {public void register(String nombres, String selectedImagePath, String email, String password){ try { // create upload service client RegisterService service = ServiceGenerator.createUser(RegisterService.class); // add another part within the multipart request RequestBody requestEmail = RequestBody.create( MediaType.parse("multipart/form-data"), email); // add another part within the multipart request RequestBody requestPassword = RequestBody.create( MediaType.parse("multipart/form-data"), password); // add another part within the multipart request RequestBody requestNombres = RequestBody.create( MediaType.parse("multipart/form-data"), nombres); MultipartBody.Part imagenPerfil = null; if(selectedImagePath!=null){ File file = new File(selectedImagePath); Log.i("Register","Nombre del archivo "+file.getName()); // 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 imagenPerfil = MultipartBody.Part.createFormData("imagenPerfil", file.getName(), requestFile); } // finally, execute the request Call<ResponseBody> call = service.registerUser(imagenPerfil, requestEmail,requestPassword,requestNombres); Response<ResponseBody> bodyResponse = call.execute(); StaticValues.code = bodyResponse.code(); StaticValues.mensaje = bodyResponse.message(); ResponseBody errorBody = bodyResponse.errorBody(); StaticValues.mensajeCodigo = errorBody==null ?null :Utilities.mensajeCodigoDeLaRespuestaJSON(bodyResponse.errorBody().byteStream()); Log.i("Register","Code "+StaticValues.code); Log.i("Register","mensaje "+StaticValues.mensaje); Log.i("Register","mensajeCodigo "+StaticValues.mensaje); } catch (Exception e){ e.printStackTrace(); }}}
In the interface of RegisterService
public interface RegisterService {@Multipart@POST(StaticValues.REGISTER)Call<ResponseBody> registerUser(@Part MultipartBody.Part image, @Part("email") RequestBody email, @Part("password") RequestBody password, @Part("nombre") RequestBody nombre);}
For the Utilities parse ofr InputStream response
public class Utilities {public static String mensajeCodigoDeLaRespuestaJSON(InputStream inputStream){ String mensajeCodigo = null; try { BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream, "iso-8859-1"), 8); StringBuilder sb = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { sb.append(line).append("\n"); } inputStream.close(); mensajeCodigo = sb.toString(); } catch (Exception e) { Log.e("Buffer Error", "Error converting result " + e.toString()); } return mensajeCodigo;}}