Android:Retrofit 2多文件上传howto?

时间:2016-01-13 22:24:00

标签: upload multiple-files retrofit2

上传单个图像似乎对改造2没有问题。

然而, 我无法弄清楚如何同时上传2张图片。

如果遵循文档: http://square.github.io/retrofit/2.x/retrofit/retrofit2/http/PartMap.html

File file = new File(path, "theimage");
File file2 = new File(path2, "theimage");
RequestBody requestBody = RequestBody.create(MediaType.parse("image/png"), file);
RequestBody requestBody2 = RequestBody.create(MediaType.parse("image/png"), file2);
Map<String, RequestBody> params = new HashMap<>();
params.put("image2", requestBody2 );

Call<ResponseBody> call = service.upload(requestBody, params);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Response<ResponseBody> response, Retrofit retrofit) {
    Log.v("Upload", "success");
}

接口:

public interface FileUploadService {

    @Multipart
    @POST("/upload")
    Call<ResponseBody> upload(
        //@Part("image_logo\"; filename=\"image.png\" ") RequestBody file,
        @Part("file") RequestBody file,
        @PartMap Map<String, RequestBody> params
     //  @Part("description") String description
);

这给了'上传:成功',但在服务器端我得到了胡言乱语:

  

CONTENT_TYPE:multipart / form-data;   边界= 50fbfeb3-3abc-4f15-B130-cdcb7e3a0e4f

     

CONTENT POST:Array(       [file] =&gt; PNGIHDRL alotofbinarygibberish .... ...剪断       [file2] =&gt; PNG       IHDR L更多二元胡言乱语......

有人能指出我正确的方向吗?

单个上传确实有效,所以不是问题,我正在尝试上传2个或更多图片。

如果我将其更改为:

HashMap<String, RequestBody> partMap = new HashMap<String, RequestBody>();
partMap.put("file\"; filename=\"" + file.getName(), requestBody);
partMap.put("file\"; filename=\"" + file2.getName(), requestBody);
Call<ResponseBody> call = service.upload(partMap);
@Multipart
@POST("/upload")
Call<ResponseBody> upload(
    @PartMap() Map<String, RequestBody> partMap,

我没有乱码,但只上传了第二张图片......!?

更新

我尝试了这个Retrofit(2.0 beta2) Multipart file upload doesn't work解决方案,但是得到了@body不能用于multipart的错误: Java.lang.IllegalArgumentException:@Body参数不能与表单或多部分编码一起使用。 (参数#1)

        for (String key : keys) {
            Bitmap bm = selectedImages.get(key);
            File f = new File(saveToInternalStorage(bm, key), key);
            if (f.exists()) {
                buildernew.addFormDataPart(key, key + ".png", RequestBody.create(MEDIA_TYPE, f));
            }
        }
        RequestBody requestBody = buildernew.build();

-

Call<ResponseBody> upload(
    @Body RequestBody requestBody

3 个答案:

答案 0 :(得分:7)

这有效:

            final MediaType MEDIA_TYPE=MediaType.parse("image/png");
            HashMap<String,RequestBody> map=new HashMap<>(selectedImages.size());
            RequestBody file=null;
            File f=null;
            Set<String> keys = selectedImages.keySet();
            for (String key : keys) {
                try {
                    Bitmap bitmap = selectedImages.get(key);
                    f = new File(saveToInternalStorage(bitmap, key), key);

                    FileOutputStream fos = new FileOutputStream(f);
                    if(bitmap!=null){
                        bitmap.compress(Bitmap.CompressFormat.PNG, 0 , fos);
                        fos.flush();
                        fos.close();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    return;
                }

                file=RequestBody.create(MEDIA_TYPE, f);
                map.put(""+key+"\"; filename=\""+key+".jpg",file);
                Log.i("##MYLOG###", "### MAP PUT:" + key + " filename:"+key+".jpg file:" + file.toString() +" type:"+ file.contentType() );
                file=null;
                f = null;
            }

-

Call<ResponseBody> upload(
        @PartMap() Map<String,RequestBody> mapFileAndName //for sending multiple images

-

注意:在使用httpClient.interceptors()进行调试时,我只看到一次上传,但在检查端点本身以查看它实际得到的内容时,它就会获得多次上传!

答案 1 :(得分:2)

我可能会迟到,但我的回答可能有助于未来的访客

我要求用户选择这样的多个图像:

int PICK_IMAGE_MULTIPLE = 1;    
Intent intent = new Intent();
       intent.setType("image/*");
       intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
       intent.setAction(Intent.ACTION_GET_CONTENT);
       startActivityForResult(Intent.createChooser(intent, "Select Picture"), PICK_IMAGE_MULTIPLE);

然后在onActivityResult()我这样做:

ArrayList<String> filePaths;

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == PICK_IMAGE_MULTIPLE) {
        if (data != null) {
            filePaths=new ArrayList<>();
            // If data.getData() == null means multiple images selected, else single image selected.
            if (data.getData() == null) {
                ClipData clipData = data.getClipData();
                if (clipData != null) {
                    for (int i = 0; i < clipData.getItemCount(); i++) {
                        ClipData.Item item = clipData.getItemAt(i);
                        Uri uri = item.getUri();
                        filePaths.add(FileUtils.getPath(Activity.this, uri));
                    }
                }
            } else {
                filePaths.add(FileUtils.getPath(Activity.this,data.getData()));
            }
            sendToServer();
        }
    }
}

您可以从this Github link

获取FileUtils课程

我的sendToServer()方法如下所示:

private void sendToServer() {
    if(filePaths!=null) {
        ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
        MediaType MEDIA_TYPE_IMG = MediaType.parse("image/jpeg");
        MultipartBody.Builder builder=new MultipartBody.Builder();
        builder.setType(MultipartBody.FORM);
        RequestBody requestBody;
        try {
            for (int i = 0; i < filePaths.size(); i++) {
                File file = new File(filePaths.get(i));
                requestBody=RequestBody.create(MEDIA_TYPE_IMG,file);
                builder.addFormDataPart("photo"+i,file.getName(),requestBody);
            }
            RequestBody finalRequestBody=builder.build();
            Call<YourResponse> call=apiService.addEvent(finalRequestBody);
            call.enqueue(new Callback<YourResponse>() {
                @Override
                public void onResponse(Call<YourResponse> call, Response<YourResponse> response) {
                    // process response
                }

                @Override
                public void onFailure(Call<YourResponse> call, Throwable t) {
                    t.printStackTrace();
                    t.getCause();
                }
            });
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

最后,我的Retrofit端点如下所示:

@POST("event/add")
Call<YourResponse> addEvent(@Body RequestBody body);

请注意,YourResponse可以是您处理回复的自定义模型类,或者您也可以使用原始Response类,而不想制作模型类。

希望这有助于新访客。

答案 2 :(得分:1)

试试这个

对于API:

//Multiple Images
@Multipart
@POST(HttpConstants.FILEMULTIPLEUPLOAD)
Call<Result>uploadMultipleImage(@Part MultipartBody.Part files1,@Part MultipartBody.Part files2, @Query("total_images") int total, @Query("stdID") int stdID);

客户端

    public class RaytaServiceClass {
        public RaytaServiceClass() {
        }

        private static Retrofit getRetroClient(){
            Gson gson = new GsonBuilder()
                    .setLenient()
                    .create();
            return new Retrofit.Builder()
                    .baseUrl(HttpConstants.baseUrl)
                    .addConverterFactory(GsonConverterFactory.create(gson))
                    .build();
        }

        public static RaytaApi getApiService(){
            return getRetroClient().create(RaytaApi.class);
        }
    }

电话

     RaytaApi service= RaytaServiceClass.getApiService();

            File file1 = new File(selectedPath1);
            File file2 = new File(selectedPath2);

            RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file1);
            RequestBody requestFile2 = RequestBody.create(MediaType.parse("multipart/form-data"), file2);


            MultipartBody.Part body =
                    MultipartBody.Part.createFormData("uploaded_file", file1.getName(), requestFile);

            MultipartBody.Part body2 =
                    MultipartBody.Part.createFormData("uploaded_file", file2.getName(), requestFile2);


            Call<Result> resultCall=service.uploadMultipleImage(body,body2,2,1);
            Log.v("@@@@WWE","REquest "+resultCall.toString());
            Log.v("@@@WWE","Retrofit Request Method =  "+resultCall.request().method());
            Log.v("@@@WWE","Retrofit Request Body =  "+resultCall.request().body());
            Log.v("@@@WWE","Retrofit Request Url = "+resultCall.request().url());
            final Result[] result = {new Result()};

            resultCall.enqueue(new Callback<Result>() {
                @Override
                public void onResponse(Call<Result> call, Response<Result> response) {
                    progressDialog.dismiss();
                    Log.v("@@@WWE","Respnse");
                    result[0] =response.body();
                    Log.v("@@@WWE","Response Result "+result[0].getResult());
                    if(response.isSuccessful()){
                        Toast.makeText(UploadMultipleImageActivity.this,"Sucess",Toast.LENGTH_SHORT).show();
                        Toast.makeText(UploadMultipleImageActivity.this,"Press Refresh Button",Toast.LENGTH_LONG).show();
                        supportFinishAfterTransition();
                    }
                }

                @Override
                public void onFailure(Call<Result> call, Throwable t) {
                    progressDialog.dismiss();
                    Log.v("@@@WWE","Failure ");
                    Log.v("@@@WWE","MEssage "+t.getMessage());
                }
            });