Пост составные данные формы с использованием Retrofit 2.0, включая изображение
Я пытаюсь сделать HTTP-сообщение на сервер с помощью Ретрофит 2.0
MediaType MEDIA_TYPE_TEXT = MediaType.parse("text/plain");
MediaType MEDIA_TYPE_IMAGE = MediaType.parse("image/*");
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
imageBitmap.compress(Bitmap.CompressFormat.JPEG, 90, byteArrayOutputStream);
profilePictureByte = byteArrayOutputStream.toByteArray();
Call<APIResults> call = ServiceAPI.updateProfile(
RequestBody.create(MEDIA_TYPE_TEXT, emailString),
RequestBody.create(MEDIA_TYPE_IMAGE, profilePictureByte));
call.enqueue();
сервер возвращает ошибку о том, что файл не является допустимым.
это странно, потому что я попытался загрузить тот же файл с тем же форматом на iOS(используя другую библиотеку), но он загружается успешно.
Мне интересно, Как правильно загрузить изображение с помощью Ретрофит 2.0?
Я должен сохранить его на диск перед загрузка?
спасибо!
P. S.: Я использовал для модернизации других многотомных запрос, который не включает в себя изображения и они завершили успешно. Проблема в том, когда я пытаюсь включить байт в тело.
7 ответов:
Я выделяю решение как в 1.9, так и в 2.0, поскольку оно полезно для некоторых
на
1.9, Я думаю, что лучшее решение-сохранить файл на диск и использовать его как типизированный файл, например:модернизация 1.9
(Я не знаю о вашей реализации на стороне сервера) есть метод интерфейса API, подобный этому
@POST("/en/Api/Results/UploadFile") void UploadFile(@Part("file")TypedFile file,@Part("folder")String folder,Callback<Response> callback);и использовать его как
TypedFile file = new TypedFile("multipart/form-data", new File(path));для дооснащения 2 используйте следующее метод
RetroFit 2.0 ( это был обходной путь для вопрос в модификации 2, которая теперь исправлена, для правильного метода см. jimmy0251 это)
интерфейс API:
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); }использовать его как:
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(); } });
есть правильно загрузка файла с его именем с Ретрофит 2, без hack:
определить интерфейс API:
@Multipart @POST("uploadAttachment") Call<MyResponse> uploadAttachment(@Part MultipartBody.Part filePart); // You can add other parameters tooЗагрузить файл следующим образом:
File file = // initialize file here MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(), RequestBody.create(MediaType.parse("image/*"), file)); Call<MyResponse> call = api.uploadAttachment(filePart);это демонстрирует только загрузку файлов, вы также можете добавить другие параметры в том же методе с
@PartПримечание.
Я использовал Retrofit 2.0 для моих пользователей регистра, отправить изображение файла multipart / form и текст из учетной записи регистра
в моем RegisterActivity, используйте AsyncTask
//AsyncTask private 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) {..}и в моем регистре.класс java-это то, где используется Retrofit с синхронным вызовом
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(); } } }в интерфейсе 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 ); }за коммунальные услуги парсинга ОФР InputStream в ответ
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; } }
Обновить код для загрузки файла изображения в Retrofit2.0
public interface ApiInterface { @Multipart @POST("user/signup") Call<UserModelResponse> updateProfilePhotoProcess(@Part("email") RequestBody email, @Part("password") RequestBody password, @Part("profile_pic\"; filename=\"pp.png\" ") RequestBody file); }изменить
MediaType.parse("image/*")доMediaType.parse("image/jpeg")RequestBody reqFile = RequestBody.create(MediaType.parse("image/jpeg"), file); RequestBody email = RequestBody.create(MediaType.parse("text/plain"), "[email protected]"); RequestBody password = RequestBody.create(MediaType.parse("text/plain"), "123456789"); Call<UserModelResponse> call = apiService.updateProfilePhotoProcess(email,password,reqFile); call.enqueue(new Callback<UserModelResponse>() { @Override public void onResponse(Call<UserModelResponse> call, Response<UserModelResponse> response) { String TAG = response.body().toString(); UserModelResponse userModelResponse = response.body(); UserModel userModel = userModelResponse.getUserModel(); Log.d("MainActivity","user image = "+userModel.getProfilePic()); } @Override public void onFailure(Call<UserModelResponse> call, Throwable t) { Toast.makeText(MainActivity.this,""+TAG,Toast.LENGTH_LONG).show(); } });
добавление к ответу, данному @insomniac. Вы можете создать
Mapпоставить параметрRequestBodyв том числе изображения.код для интерфейса
public interface ApiInterface { @Multipart @POST("/api/Accounts/editaccount") Call<User> editUser (@Header("Authorization") String authorization, @PartMap Map<String, RequestBody> map); }код для класса Java
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)); Map<String, RequestBody> map = new HashMap<>(); map.put("file\"; filename=\"pp.png\" ", fbody); map.put("FirstName", name); map.put("Id", id); Call<User> call = client.editUser(AZUtils.getToken(this), map); 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(); } });
загрузка файлов с помощью Retrofit довольно проста вам нужно построить свой интерфейс api как
public interface Api { String BASE_URL = "http://192.168.43.124/ImageUploadApi/"; @Multipart @POST("yourapipath") Call<MyResponse> uploadImage(@Part("image\"; filename=\"myfile.jpg\" ") RequestBody file, @Part("desc") RequestBody desc); }В приведенном выше коде изображения - это имя ключа, так что если вы используете PHP, вы будете писать $_FILES ['image'] ['tmp_name'] чтобы сделать это. И filename= " myfile.jpg" - это имя файла, который отправляется вместе с запросом.
Теперь для загрузки файла вам нужен метод, который даст вам абсолютный путь от Uri.
private String getRealPathFromURI(Uri contentUri) { String[] proj = {MediaStore.Images.Media.DATA}; CursorLoader loader = new CursorLoader(this, contentUri, proj, null, null, null); Cursor cursor = loader.loadInBackground(); int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); String result = cursor.getString(column_index); cursor.close(); return result; }Теперь вы можете использовать приведенный ниже код для загрузки файла.
private void uploadFile(Uri fileUri, String desc) { //creating a file File file = new File(getRealPathFromURI(fileUri)); //creating request body for file RequestBody requestFile = RequestBody.create(MediaType.parse(getContentResolver().getType(fileUri)), file); RequestBody descBody = RequestBody.create(MediaType.parse("text/plain"), desc); //The gson builder Gson gson = new GsonBuilder() .setLenient() .create(); //creating retrofit object Retrofit retrofit = new Retrofit.Builder() .baseUrl(Api.BASE_URL) .addConverterFactory(GsonConverterFactory.create(gson)) .build(); //creating our api Api api = retrofit.create(Api.class); //creating a call and calling the upload image method Call<MyResponse> call = api.uploadImage(requestFile, descBody); //finally performing the call call.enqueue(new Callback<MyResponse>() { @Override public void onResponse(Call<MyResponse> call, Response<MyResponse> response) { if (!response.body().error) { Toast.makeText(getApplicationContext(), "File Uploaded Successfully...", Toast.LENGTH_LONG).show(); } else { Toast.makeText(getApplicationContext(), "Some error occurred...", Toast.LENGTH_LONG).show(); } } @Override public void onFailure(Call<MyResponse> call, Throwable t) { Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show(); } }); }для более подробного объяснения вы можете посетить это Retrofit Загрузить Файл Учебник.
так что его очень простой способ для достижения вашей задачи. Вы должны следовать ниже Шаг :-
1. Первый шаг
public interface APIService { @Multipart @POST("upload") Call<ResponseBody> upload( @Part("item") RequestBody description, @Part("imageNumber") RequestBody description, @Part MultipartBody.Part imageFile ); }вам нужно сделать весь вызов как
@Multipart request.itemиimage numberэто просто строка тело, которое завернуто вRequestBody. Мы используемMultipartBody.Part classэто позволяет нам отправить фактическое имя файла, кроме двоичных данных файла с запросом2. Второй шаг
File file = (File) params[0]; RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file); MultipartBody.Part body =MultipartBody.Part.createFormData("Image", file.getName(), requestBody); RequestBody ItemId = RequestBody.create(okhttp3.MultipartBody.FORM, "22"); RequestBody ImageNumber = RequestBody.create(okhttp3.MultipartBody.FORM,"1"); final Call<UploadImageResponse> request = apiService.uploadItemImage(body, ItemId,ImageNumber);теперь у вас есть
image pathи вам нужно преобразовать вfile.Теперь конвертироватьfileнаRequestBodyметодомRequestBody.create(MediaType.parse("multipart/form-data"), file). Теперь вам нужно преобразовать вашRequestBody requestFileнаMultipartBody.PartметодомMultipartBody.Part.createFormData("Image", file.getName(), requestBody);.
ImageNumberиItemIdэто мои другие данные, которые мне нужно отправить на сервер, поэтому я также делаю обе вещи вRequestBody.
Comments