J'essaye de faire un HTTP POST au serveur en utilisant Retrofit 2.
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();
Le serveur renvoie une erreur en indiquant que le fichier n'est pas valide.
C'est bizarre parce que j'ai essayé de télécharger le même fichier avec le même format sur iOS (en utilisant une autre bibliothèque), mais le téléchargement a réussi.
Je me demande quelle est la bonne façon de télécharger une image en utilisant Retrofit 2.?
Dois-je l'enregistrer sur le disque avant de télécharger?
P.S .: J'ai utilisé la modification pour une autre demande multipart n'incluant pas d'image et elles se sont bien déroulées. Le problème, c'est quand j'essaie d'inclure un octet dans le corps.
Je souligne la solution dans les versions 1.9 et 2.0 car elle est utile pour certains
Dans 1.9
, je pense que la meilleure solution consiste à enregistrer le fichier sur le disque et à l’utiliser comme fichier typé comme:
(Je ne sais pas à propos de votre implémentation côté serveur) avoir une méthode d'interface API similaire à celle-ci
@POST("/en/Api/Results/UploadFile")
void UploadFile(@Part("file")TypedFile file,@Part("folder")String folder,Callback<Response> callback);
Et l'utiliser comme
TypedFile file = new TypedFile("multipart/form-data", new File(path));
Interface 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);
}
Utilisez-le comme:
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();
}
});
Il y a un moyen correct de télécharger un fichier avec son nom avec Retrofit 2, sans aucun bidouille:
Définir l'interface API:
@Multipart
@POST("uploadAttachment")
Call<MyResponse> uploadAttachment(@Part MultipartBody.Part filePart);
// You can add other parameters too
Téléchargez le fichier comme ceci:
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);
Ceci illustre uniquement le téléchargement de fichier, vous pouvez également ajouter d'autres paramètres dans la même méthode avec l'annotation @Part
.
J'ai utilisé Retrofit 2.0 pour mes utilisateurs de registre, envoi d'une image de fichier multipart/form et du texte du compte de registre
Dans mon RegisterActivity, utilisez une 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) {..}
Et dans ma classe Register.Java, c’est l’utilisation où Retrofit avec appel synchrone
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();
}
}
}
Dans l'interface de 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
);
}
Pour l'analyse des utilitaires de la réponse 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;
}
}
Code de mise à jour pour le téléchargement du fichier image dans Retrofit2.
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);
}
Remplacez MediaType.parse("image/*")
par 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();
}
});
Ajout à la réponse donnée par @insomniac. Vous pouvez créer un Map
pour mettre le paramètre pour RequestBody
avec une image.
Code pour l'interface
public interface ApiInterface {
@Multipart
@POST("/api/Accounts/editaccount")
Call<User> editUser (@Header("Authorization") String authorization, @PartMap Map<String, RequestBody> map);
}
Code pour la classe 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();
}
});
C'est donc un moyen très simple d'accomplir votre tâche. Vous devez suivre l'étape ci-dessous: -
1. Première étape
public interface APIService {
@Multipart
@POST("upload")
Call<ResponseBody> upload(
@Part("item") RequestBody description,
@Part("imageNumber") RequestBody description,
@Part MultipartBody.Part imageFile
);
}
Vous devez faire tout l'appel en tant que @Multipart request
. item
et image number
est simplement un corps de chaîne entouré de RequestBody
. Nous utilisons le MultipartBody.Part class
qui nous permet d’envoyer le nom de fichier actuel en plus des données du fichier binaire avec la requête
2. Deuxième étape
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);
Maintenant, vous avez image path
et vous devez convertir en file
. Maintenant, convertissez file
en RequestBody
en utilisant la méthode RequestBody.create(MediaType.parse("multipart/form-data"), file)
. Vous devez maintenant convertir votre RequestBody requestFile
en MultipartBody.Part
à l'aide de la méthode MultipartBody.Part.createFormData("Image", file.getName(), requestBody);
.
ImageNumber
et ItemId
sont mes autres données que je dois envoyer au serveur afin que je puisse également créer les deux en RequestBody
.
Le téléchargement de fichiers à l’aide de Retrofit est très simple. Vous devez créer votre interface 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);
}
dans le code ci-dessus image est le nom de la clé, donc si vous utilisez php, vous écrirez $ _ FILES ['image '] [' tmp_name '] pour l'obtenir. Et filename = "myfile.jpg" est le nom de votre fichier qui est envoyé avec la demande.
Maintenant, pour télécharger le fichier, vous avez besoin d’une méthode qui vous donnera le chemin absolu depuis l’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;
}
Maintenant, vous pouvez utiliser le code ci-dessous pour télécharger votre fichier.
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();
}
});
}
Pour une explication plus détaillée, vous pouvez visiter ce tutoriel de téléchargement de fichier de modernisation.