8

How can i upload multi file using retrofit,

i tried to upload file using this code :

ApiService:

@Multipart
@POST("uploadData.php")
Call<ServerResponse> uploadFile(@Part MultipartBody.Part file,
                                @Part("name") RequestBody name,
                                @Part MultipartBody.Part img,
                                @Part("imgname") RequestBody imgname);

and the upload method:

private void uploadFile() {
    File file = new File(Environment.getExternalStorageDirectory() + "/Download/audio2.wav");
    File file2 = new File(Environment.getExternalStorageDirectory() + "/Download/Salty.png");

    RequestBody mFile = RequestBody.create(MediaType.parse("audio/*"), file);
    MultipartBody.Part fileToUpload = MultipartBody.Part.createFormData("file", file.getName(), mFile);
    RequestBody filename = RequestBody.create(MediaType.parse("text/plain"), file.getName());

    RequestBody mFile2 = RequestBody.create(MediaType.parse("image/*"), file2);
    MultipartBody.Part fileToUpload2 = MultipartBody.Part.createFormData("file", file2.getName(), mFile2);
    RequestBody filename2 = RequestBody.create(MediaType.parse("text/plain"), file2.getName());

    ApiService uploadImage = ApiClient.getClient().create(ApiService.class);
    Call<ServerResponse> fileUpload = uploadImage.uploadFile(fileToUpload, filename, fileToUpload2, filename2);
    fileUpload.enqueue(new Callback<ServerResponse>() {
            @Override
            public void onResponse(Call<ServerResponse> call, Response<ServerResponse> response) {
                Toast.makeText(MainActivity.this, "Success " + response.message(), Toast.LENGTH_LONG).show();
                Toast.makeText(MainActivity.this, "Success " + response.body().toString(), Toast.LENGTH_LONG).show();
            }

            @Override
            public void onFailure(Call<ServerResponse> call, Throwable t) {
                Log.d("TAG", "Error " + t.getMessage());
            }
    });
}

and php code:

$result = array("success" => $_FILES["file"]["name"]);
$file_path = basename($_FILES['file']['name']);

$imgResult = array("success" => $_FILES["img"]["imgname"]);
$img_path = basename($_FILES['img']['imgname']);


if (move_uploaded_file($_FILES['img']['tmp_name2'], "$img_path") or
        move_uploaded_file($_FILES['file']['tmp_name'], "$file_path")) {
    $result = array("success" => "File successfully uploaded");
} else {
    $result = array("success" => "error uploading file");
}

echo json_encode($result, JSON_PRETTY_PRINT);

this code works only for one file and i don't know the reason,

any help, Thanks in advance.

4 Answers4

3

You have to change code as to upload for multiple file in single request using retrofit as below.

Create a function which creates MultiPartBody.Part and will get its type extenstion automatically.

public static MultipartBody.Part prepareFilePart(String partName, String fileUri) {
    File file = new File(fileUri);
    String mimeType= URLConnection.guessContentTypeFromName(file.getName());
    Log.e("mimeType",mimeType);
    //create RequestBody instance from file
    RequestBody requestFile = RequestBody.create(MediaType.parse(mimeType), file);
    //MultipartBody.Part is used to send also the actual file name
    return MultipartBody.Part.createFormData(partName, file.getName(), requestFile);
}

Now in your code, to upload multiple file, create ArrayList<MultiPartBody.Part> as below.

public void uploadFile(){
    ArrayList<MultiPartBody.Part> files = new ArrayList<MultiPartBody.Part>();

    for(int i=0; i < selectedFiles.size; i++){
        files.add(prepareFilePart("file_"+(i+1), selectedFiles.get(i)));
        //Where selectedFiles is selected file URI list
    }

    RequestBody totalFiles = RequestBody.create(MediaType.parse("text/plain"), files.size);

    ApiService uploadImage = ApiClient.getClient().create(ApiService.class);
    Call<ServerResponse> fileUpload = uploadImage.uploadFile(files,totalFiles);
    fileUpload.enqueue(...);

}

and in your ApiService, make a change as

@Multipart
@POST("uploadData.php")
Call<ServerResponse> uploadFile(@Part ArrayLisy<MultipartBody.Part> files, @Part("totalFiles") RequestBody totalFiles);

and in your PHP file make a code change as

$totalFiles = $_REQUEST['totalFiles'];
$successUpload = 0;

for($i=1; $i <= $totalFiles; $i++){
    $fileName = 'file_'.$i;
    if(move_uploaded_file($_FILES[$fileName]['tmp_name'],"Valid_file_path"){
        $successUpload += 1;
    }
}

echo $successUpload.' Files uploaded successfully.';
Chintak Patel
  • 718
  • 5
  • 22
2

No Need to pass your filenames from Android, after you receive a file then get that filename here itself(in PHP Code)

@Multipart
@POST("uploadData.php")
Call<ServerResponse> uploadFile(@Part MultipartBody.Part file,
                                @Part MultipartBody.Part img);

File Upload code in Java

MultipartBody.Part audioFile= null;
        try {
            File file = new File(Environment.getExternalStorageDirectory() + "/Download/audio2.wav");
            if file != null) {                
                RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"),
                        file);
                audioFile = MultipartBody.Part.createFormData("AudioFile", file.getName(), requestFile);
            }
        }
        catch (Exception ex)
        {
            Log.d("UploadStatus", "Multipart Audio as exception occurs");
        }

MultipartBody.Part imageFile = null;
        try {
            File file = new File(Environment.getExternalStorageDirectory() + "/Download/Salty.png");
            if file != null) {                
                RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"),
                        file);
                imageFile = MultipartBody.Part.createFormData("ImageFile", file.getName(), requestFile);
            }
        }
        catch (Exception ex)
        {
            Log.d("UploadStatus", "Multipart Image as exception occurs");
        }


ApiService uploadImage = ApiClient.getClient().create(ApiService.class);
    Call<ServerResponse> fileUpload = uploadImage.uploadFile(audioFile, imageFile);
    fileUpload.enqueue(new Callback<ServerResponse>() {
            @Override
            public void onResponse(Call<ServerResponse> call, Response<ServerResponse> response) {
                Toast.makeText(MainActivity.this, "Success " + response.message(), Toast.LENGTH_LONG).show();
                Toast.makeText(MainActivity.this, "Success " + response.body().toString(), Toast.LENGTH_LONG).show();
            }

            @Override
            public void onFailure(Call<ServerResponse> call, Throwable t) {
                Log.d("TAG", "Error " + t.getMessage());
            }
    });

in your PHP Code

access that two files like

file 1    ==>   $_FILES["AudioFile"]["name"]

file 1    ==>   $_FILES["ImageFile"]["name"]

then get your file names here...

You have to avoid the facing setLenient error on your retrofit Builder

Gson gson = new GsonBuilder()
        .setLenient()
        .create();

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(BASE_URL)
        .client(client)
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build(); 

Hope this will help you...

Raja
  • 2,606
  • 2
  • 16
  • 30
  • Hello Raja, sorry for late reply , i got this error Error `Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $` – Mohamed Salama Apr 14 '18 at 23:15
1

as above answer by @chintak is correct, you need to add

Gson gson = new GsonBuilder()
.setLenient()
.create();

Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()

as mentioned in above comment by you, that you are facing Lenient Malformed Exception.

Kousei
  • 1,291
  • 1
  • 7
  • 15
  • Hello Kousei, Sorry for late reply , i got this error `com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $` – Mohamed Salama Apr 14 '18 at 23:19
  • you can check this question https://stackoverflow.com/questions/28418662/expected-begin-object-but-was-string-at-line-1-column-1 – Kousei Apr 15 '18 at 05:24
0

Api Interface :

  @Multipart
        @POST("Shareds/AddShared")
        Call<ResponseBody> UPLOAD_PHOTO_CALL(
                @Part List<MultipartBody.Part> files);



List<MultipartBody.Part> parts = new ArrayList<>();

**and then fill your parts with for loop :D** 

RequestBody reqFile = RequestBody.create(compressedImgFile, MediaType.parse("image/*"));
            parts.add(MultipartBody.Part.createFormData("files", file.getName(), reqFile));



retrofit = new Retrofit.Builder()
                .baseUrl(TEST_URL)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .addConverterFactory(**ScalarsConverterFactory.create()**)
                .client(builder.build())
                .build();
        return retrofit;
tsniso
  • 323
  • 3
  • 14