Android Learning
HomeBlogAbout

Android Learning

Learn Android development with comprehensive tutorials, guides, and best practices. From beginner to advanced Android programming.

Quick Links

  • Home
  • Blog
  • About
  • Contact
  • Newsletter

Resources

  • Android Developers
  • Kotlin Docs
  • Jetpack Compose

© 2026 Android Learning. All rights reserved.

Privacy PolicyTerms of Service
Back to Blog
May 7, 2018
15 min read
Akshay Raj

Upload Multiple Images Using Retrofit Library

Upload Multiple Images Using Retrofit Library

Akshay Raj

Android development expert

In this tutorial, we will upload multiple images to server using Retrofit Library.

Creating Server Side Codes

  • Go to your server’s root directory (c:/wamp/www) and create a new folder. I created UploadImage.
  • Inside the folder create a folder named uploads, in this folder, we will save all the uploaded images.
  • Create a file named upload.php and write the following code.
    <?php
    // Path to move uploaded files
    $target_path = dirname(__FILE__).'/uploads/';
    $size = $_POST['size'];
    if (!empty($_FILES)) {
        for ($x = 0; $x < $size; $x++) {
            try {
                $newname = date('YmdHis',time()).mt_rand().'.jpg';
                // Throws exception incase file is not being moved
                if (!move_uploaded_file($_FILES['image'.$x]['tmp_name'], $target_path .$newname)) {
                    // make error flag true
                    echo json_encode(array('status'=>'fail', 'message'=>'could not move file'));
                }
                // File successfully uploaded
                echo json_encode(array('status'=>'success', 'message'=>'File Uploaded'));
            } catch (Exception $e) {
                // Exception occurred. Make error flag true
                echo json_encode(array('status'=>'fail', 'message'=>$e->getMessage()));
            }
        }
    } else {
        // File parameter is missing
        echo json_encode(array('status'=>'fail', 'message'=>'Not received any file'));
    }

Create Android Project

  • Open Android Studio and create a project. How to create an android project?
  • Now open Build.gradle file of app directory and add Retrofit2’s compile dependency as shown below :
    implementation 'com.squareup.retrofit2:retrofit:2.6.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.6.0'
  • Add Glide library for showing selected images
    implementation 'com.github.bumptech.glide:glide:4.10.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.10.0'
  • Complete dependencies block:
    dependencies {
        implementation fileTree(include: ['*.jar'], dir: 'libs')
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'androidx.test.ext:junit:1.1.1'
        androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
        implementation 'androidx.appcompat:appcompat:1.1.0'
        implementation 'com.google.android.material:material:1.0.0'
        implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
        implementation 'com.squareup.retrofit2:retrofit:2.6.2'
        implementation 'com.squareup.retrofit2:converter-gson:2.6.2'
        implementation 'com.github.bumptech.glide:glide:4.10.0'
        annotationProcessor 'com.github.bumptech.glide:compiler:4.10.0'
    }
  • Now click on Sync Now or Sync Project With Gradle Icon from the top menu
  • Now create the following layout with below codes. Android Upload Multiple Images
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="16dp">
    
        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Upload Multiple Files"
            android:textColor="#000"
            android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"/>
    
        <com.google.android.material.button.MaterialButton
            android:id="@+id/btnChoose"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="Choose Image"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/textView"
            app:layout_constraintEnd_toStartOf="@id/btnUpload"/>
    
        <com.google.android.material.button.MaterialButton
            android:id="@+id/btnUpload"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="Upload"
            app:layout_constraintStart_toEndOf="@id/btnChoose"
            app:layout_constraintTop_toBottomOf="@id/textView"
            app:layout_constraintEnd_toEndOf="parent"/>
    
        <ProgressBar
            android:id="@+id/progressBar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:visibility="gone"
            app:layout_constraintStart_toEndOf="@id/btnChoose"
            app:layout_constraintTop_toBottomOf="@id/textView"
            app:layout_constraintEnd_toEndOf="parent"/>
    
        <ListView
            android:id="@+id/listView"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_marginTop="15dp"
            app:layout_constraintTop_toBottomOf="@id/btnChoose"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"/>
    
    </androidx.constraintlayout.widget.ConstraintLayout>
  • Now connect ListView, Buttons, and Progressbar to activity.
    public class MainActivity extends AppCompatActivity {
    ...
    private ListView listView;
    private ProgressBar mProgressBar;
    private MaterialButton btnChoose, btnUpload;
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
        listView = findViewById(R.id.listView);
        mProgressBar = findViewById(R.id.progressBar);
        btnChoose = findViewById(R.id.btnChoose);
        btnUpload = findViewById(R.id.btnUpload);
        ...
    }
  • Create Image Chooser and Runtime Permission to choose image button. Learn Runtime Permission.
    btnChoose.setOnClickListener(v -> {
                // Display the file chooser dialog
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    askForPermission();
                } else {
                    showChooser();
                }
            });
    ...
    
    private void showChooser() {
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType("image/*");
        intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        startActivityForResult(intent, REQUEST_CODE_READ_STORAGE);
    }
    
    ...
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent resultData) {
        super.onActivityResult(requestCode, resultCode, resultData);
        if (resultCode == RESULT_OK) {
            if (requestCode == REQUEST_CODE_READ_STORAGE) {
                if (resultData != null) {
                    if (resultData.getClipData() != null) {
                        int count = resultData.getClipData().getItemCount();
                        int currentItem = 0;
                        while (currentItem < count) {
                            Uri imageUri = resultData.getClipData().getItemAt(currentItem).getUri();
                            currentItem = currentItem + 1;
    
                            Log.d("Uri Selected", imageUri.toString());
    
                            try {
                                arrayList.add(imageUri);
                                MyAdapter mAdapter = new MyAdapter(MainActivity.this, arrayList);
                                listView.setAdapter(mAdapter);
    
                            } catch (Exception e) {
                                Log.e(TAG, "File select error", e);
                            }
                        }
                    } else if (resultData.getData() != null) {
    
                        final Uri uri = resultData.getData();
                        Log.i(TAG, "Uri = " + uri.toString());
    
                        try {
                            arrayList.add(uri);
                            MyAdapter mAdapter = new MyAdapter(MainActivity.this, arrayList);
                            listView.setAdapter(mAdapter);
    
                        } catch (Exception e) {
                            Log.e(TAG, "File select error", e);
                        }
                    }
                }
            }
        }
    }
  • Create a Base Adapter for showing multiple images in the list
    public class MyAdapter extends BaseAdapter {
        private Context context;
        private ArrayList<Uri> arrayList;
    
        ...
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            LayoutInflater mInflater = LayoutInflater.from(context);
            if (mInflater != null) {
                convertView = mInflater.inflate(R.layout.list_items, parent, false);
            }
    
            ImageView imageView = convertView.findViewById(R.id.imageView);
            TextView imagePath = convertView.findViewById(R.id.imagePath);
    
            imagePath.setText(FileUtils.getPath(context, arrayList.get(position)));
    
            Glide.with(context)
                    .load(arrayList.get(position))
                    .into(imageView);
    
            return convertView;
        }
    
        ....
    
    }
  • Create a layout for the list
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="10dp">
    
        <ImageView
            android:id="@+id/imageView"
            android:layout_width="90dp"
            android:layout_height="90dp"
            android:contentDescription="ImageView"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>
    
        <TextView
            android:id="@+id/imagePath"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
            android:textColor="#000"
            app:layout_constraintStart_toEndOf="@id/imageView"
            app:layout_constraintTop_toTopOf="parent"/>
    
    </androidx.constraintlayout.widget.ConstraintLayout>
  • Upload Images to the server with Retrofit
    btnUpload.setOnClickListener(v -> uploadImagesToServer());
  • Create Retrofit client
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(ApiService.BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    
    // create list of file parts (photo, video, ...)
    List<MultipartBody.Part> parts = new ArrayList<>();
    
    // create upload service client
    ApiService service = retrofit.create(ApiService.class);
    
    if (arrayList != null) {
        // create part for file (photo, video, ...)
        for (int i = 0; i < arrayList.size(); i++) {
            parts.add(prepareFilePart("image"+i, arrayList.get(i)));
        }
    }
    
    // create a map of data to pass along
    RequestBody description = createPartFromString("www.androidlearning.com");
    RequestBody size = createPartFromString(""+parts.size());
    
    // finally, execute the request
    Call<ResponseBody> call = service.uploadMultiple(description, size, parts);
    
    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(@NonNull Call<ResponseBody> call, @NonNull Response<ResponseBody> response) {
            .....
        }
    
        @Override
        public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) {
            .....
        }
    });
  • Convert String and File to Multipart for Retrofit Library
    @NonNull
    private RequestBody createPartFromString(String descriptionString) {
        return RequestBody.create(MediaType.parse(FileUtils.MIME_TYPE_TEXT), descriptionString);
    }
    
    @NonNull
    private MultipartBody.Part prepareFilePart(String partName, Uri fileUri) {
        // use the FileUtils to get the actual file by uri
        File file = FileUtils.getFile(this, fileUri);
    
        // create RequestBody instance from file
        RequestBody requestFile = RequestBody.create (MediaType.parse(FileUtils.MIME_TYPE_IMAGE), file);
    
        // MultipartBody.Part is used to send also the actual file name
        return MultipartBody.Part.createFormData(partName, file.getName(), requestFile);
    }
  • In the last, you need to add Runtime Permissions Request to run the app in Android 6 and above
  • Now run your app and upload multiple files (images, videos, songs, and other files...)  Android Upload Multiple Images Android Upload Multiple Images

Download Full Project

Download Project

Enter your email to unlock the download.

Tags

#advance android#android#android learning#camera#gallery#image upload#imageview#multiple image

Comments

Krishna Mohan Danda•May 9, 2018
Hi, I am adding one image, string and int values sent through multipart. it is not working. Please help me
1 reply
Akshay Raj•May 9, 2018
send string instead of int
mirul•Sep 24, 2018
hi thanks for your sharing, i just try on Android 6. nWhy application crash? n
1 reply
Akshay Raj•Sep 24, 2018
You need to add runtime permissions because android 6 not allowed storage permission
mirul•Sep 24, 2018
Thanks for your sharing, but why on android 6 is crash
Segun emmanuel•Oct 7, 2018
Please this script cannot upload more than five(5) images at a time. I am write a program that needs up to 25 images to be uploaded at once. please how do i go about it
1 reply
Akshay Raj•Oct 10, 2018
update your php.ini because php.ini have limits (http://php.net/manual/en/ini.core.php#ini.max-file-uploads)
M. Rizky•Feb 9, 2019
thank you very much, it saved my life
Ahmer•Feb 21, 2019
I keep getting “something went wrong” notification, Please help.

Enjoyed this article?

Subscribe to our newsletter to get more articles like this delivered to your inbox.