Android Upload Multiple Images

Upload Multiple Images Using Retrofit Library

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.3.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
  • Add Glide library for showing selected images
    implementation 'com.github.bumptech.glide:glide:4.2.0'
  • Complete dependencies block:
    dependencies {
        implementation fileTree(include: ['*.jar'], dir: 'libs')
        implementation 'com.android.support:appcompat-v7:27.1.1'
        implementation 'com.android.support:design:27.1.1'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'com.android.support.test:runner:1.0.2'
        androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
        implementation 'com.squareup.retrofit2:retrofit:2.3.0'
        implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
        implementation 'com.github.bumptech.glide:glide:4.2.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"?>
    <android.support.design.widget.CoordinatorLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/parent_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <TextView
                android:id="@+id/textView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:padding="16dp"
                android:layout_gravity="center"
                android:text="Upload Multiple Files"
                android:textAppearance="@style/TextAppearance.AppCompat.Large" />
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:layout_marginBottom="10dp">
                <Button
                    android:id="@+id/btnChoose"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Choose Image"/>
                <Button
                    android:id="@+id/btnUpload"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Upload"/>
                <ProgressBar
                    android:id="@+id/progressBar"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:visibility="gone"/>
            </LinearLayout>
            <ListView
                android:id="@+id/listView"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
        </LinearLayout>
    </android.support.design.widget.CoordinatorLayout>
  • Now connect ListView, Buttons, and Progressbar to activity.
    public class MainActivity extends AppCompatActivity {
    ...
    private ListView listView;
    private ProgressBar mProgressBar;
    private Button 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(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // Display the file chooser dialog
            if (askForPermission())
                showChooser();
        }
    });
    ...
    private void showChooser() {
       // Use the GET_CONTENT intent from the utility class
       Intent target = FileUtils.createGetContentIntent();
       // Create the chooser Intent
       Intent intent = Intent.createChooser(
               target, getString(R.string.chooser_title));
       try {
           startActivityForResult(intent, REQUEST_CODE);
       } catch (ActivityNotFoundException e) {
           // The reason for the existence of aFileChooser
       }
    }
    ...
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case REQUEST_CODE:
                // If the file selection was successful
                if (resultCode == RESULT_OK) {
                    if(data.getClipData() != null) {
                        int count = data.getClipData().getItemCount();
                        int currentItem = 0;
                        while(currentItem < count) {
                            Uri imageUri = data.getClipData().getItemAt(currentItem).getUri();
                            //do something with the image (save it to some directory or whatever you need to do with it here)
                            currentItem = currentItem + 1;
                            Log.d("Uri Selected", imageUri.toString());
                            try {
                                // Get the file path from the URI
                                String path = FileUtils.getPath(this, imageUri);
                                Log.d("Multiple File Selected", path);
                                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(data.getData() != null) {
                        //do something with the image (save it to some directory or whatever you need to do with it here)
                        final Uri uri = data.getData();
                        Log.i(TAG, "Uri = " + uri.toString());
                        try {
                            // Get the file path from the URI
                            final String path = FileUtils.getPath(this, uri);
                            Log.d("Single File Selected", path);
                            arrayList.add(uri);
                            MyAdapter mAdapter = new MyAdapter(MainActivity.this, arrayList);
                            listView.setAdapter(mAdapter);
                        } catch (Exception e) {
                            Log.e(TAG, "File select error", e);
                        }
                    }
                }
                break;
        }
        super.onActivityResult(requestCode, resultCode, data);
    }
  • Create an adapter for showing multiple images in the list
    public class MyAdapter extends BaseAdapter {
        private Context context;
        private ArrayList<Uri> arrayList;
        public MyAdapter(Context context, ArrayList<Uri> arrayList) {
            this.context = context;
            this.arrayList = arrayList;
        }
        @Override
        public int getCount() {
            return arrayList.size();
        }
        @Override
        public Object getItem(int position) {
            return arrayList.get(position);
        }
        @Override
        public long getItemId(int position) {
            return position;
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            if (mInflater != null) {
                convertView = mInflater.inflate(R.layout.list_items, null);
            }
            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"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="5dp">
        <ImageView
            android:id="@+id/imageView"
            android:layout_width="90dp"
            android:layout_height="90dp" />
        <TextView
            android:id="@+id/imagePath"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:textSize="17sp"
            android:textColor="#000"/>
    </LinearLayout>
  • Upload Images to the server with Retrofit
    btnUpload.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            uploadImagesToServer();
        }
    });
    ...
    private void uploadImagesToServer() {
        if (InternetConnection.checkConnection(MainActivity.this)) {
            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://192.168.43.166/~snow/UploadImage/")
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
            showProgress();
            // 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) {
                    hideProgress();
                    if(response.isSuccessful()) {
                        Toast.makeText(MainActivity.this,
                                "Images successfully uploaded!", Toast.LENGTH_SHORT).show();
                    } else {
                        Snackbar.make(parentView, R.string.string_some_thing_wrong, Snackbar.LENGTH_LONG).show();
                    }
                }
                @Override
                public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) {
                    hideProgress();
                    Snackbar.make(parentView, t.getMessage(), Snackbar.LENGTH_LONG).show();
                }
            });
        } else {
            hideProgress();
            Toast.makeText(MainActivity.this,
                    R.string.string_internet_connection_not_available, Toast.LENGTH_SHORT).show();
        }
    }
    ...
  • Convert String and File to Multipart for Retrofit Library
    @NonNull
    private RequestBody createPartFromString(String descriptionString) {
        return RequestBody.create(
                okhttp3.MultipartBody.FORM, descriptionString);
    }
    @NonNull
    private MultipartBody.Part prepareFilePart(String partName, Uri fileUri) {
        // https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java
        // 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(Objects.requireNonNull(getContentResolver().getType(fileUri))),
                        file
                );
        // MultipartBody.Part is used to send also the actual file name
        return MultipartBody.Part.createFormData(partName, file.getName(), requestFile);
    }
  • 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

About the author

Akshay Raj

View all posts

7 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *