How to pick multiple files from android poster

How to pick multiple files from Android

In this tutorial, I am explaining how to pick multiple files in android using the default file chooser. By using this example, you can select images and files. In my previous post, I have explained how to capture images using a content provider.

Step to pick multiple files in android

  • Setup file picking intent for multiple files and registerForActivityResult.
  • on activity result get the select files URI.
  • Store the image in defined location from the URI.
  • Display the image from the file location.

Setup File Picking Intent

Once we got the permission next step is to set up the intent to pick multiple images from the gallery or from another location.

val selectImagesActivityResult =
            registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
                if (result.resultCode == Activity.RESULT_OK) {
                    
                }
            }
val intent = Intent(ACTION_GET_CONTENT)
            intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
            intent.type = "*/*"
            selectImagesActivityResult.launch(intent)

In the above code,

Intent.EXTRA_ALLOW_MULTIPLE to true set the intent to select multiple files.

intent.type = “*/*to allow intent to accept all kinds of files like images, pdf and etc.

if you want to allow only images, use intent.type = “image/*

Finally, register startActivityResult with the intent we created. This is redirected to the default file chooser to select our needed files.

Get File URI from result

Once all the files are selected, It will come to the Activity result with the result as a response. The result contains Intent with data.

If you user-selected multiple images, it will come to the intent clipData and the user selected only one image then we need to check it in intent data.

val selectImagesActivityResult =
            registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
                if (result.resultCode == Activity.RESULT_OK) {
                    val data: Intent? = result.data
                    //If multiple image selected
                    if (data?.clipData != null) {
                        val count = data.clipData?.itemCount ?: 0
                        for (i in 0 until count) {
                            val imageUri: Uri? = data.clipData?.getItemAt(i)?.uri
                        }
                    }
                    //If single image selected
                    else if (data?.data != null) {
                        val imageUri: Uri? = data.data
                    }
                }
            }

If multiple files are selected, clipData has all the selected files URI. So, loop through the clipdata and get all the file URI.

Get File From URI

Now we are having the URI of the selected files. Let get the File from the URI. I have created a method to get the Files from the URI.

private fun getImageFromUri(imageUri: Uri?) : File? {
        imageUri?.let { uri ->
            val mimeType = getMimeType(this@MainActivity, uri)
            mimeType?.let {
                val file = createTmpFileFromUri(this, imageUri,"temp_image", ".$it")
                file?.let { Log.d("image Url = ", file.absolutePath) }
                return file
            }
        }
        return null
    }


    private fun getMimeType(context: Context, uri: Uri): String? {
        //Check uri format to avoid null
        val extension: String? = if (uri.scheme == ContentResolver.SCHEME_CONTENT) {
            //If scheme is a content
            val mime = MimeTypeMap.getSingleton()
            mime.getExtensionFromMimeType(context.contentResolver.getType(uri))
        } else {
            //If scheme is a File
            //This will replace white spaces with %20 and also other special characters. This will avoid returning null values on file name with spaces and special characters.
            MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(File(uri.path)).toString())
        }
        return extension
    }

    private fun createTmpFileFromUri(context: Context, uri: Uri, fileName: String, mimeType: String): File? {
        return try {
            val stream = context.contentResolver.openInputStream(uri)
            val file = File.createTempFile(fileName, mimeType,cacheDir)
            FileUtils.copyInputStreamToFile(stream,file)
            file
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }

in the above code, The createTmpFileFromUri() creates the Temp file in the cache directory and writes the selected file in the cache directory using the given URI. The getMimeType() get the type of the file like pdf or jpg.

Finally, getImageFromUri() will return the file location where the selected images are stored in the cache directory.

Display the selected Files

Now we got the file locations of the selected images. let load the files into recyclerview and display. In this example, I have selected images and displayed images in recyclerview.

lateinit var imageAdapter: ImageAdapter
var selectedPaths = mutableListOf<String>()
imageAdapter = ImageAdapter()
rvImages.adapter = imageAdapter

val selectImagesActivityResult =
            registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
                if (result.resultCode == Activity.RESULT_OK) {
                    val data: Intent? = result.data
                    //If multiple image selected
                    if (data?.clipData != null) {
                        val count = data.clipData?.itemCount ?: 0

                        for (i in 0 until count) {
                            val imageUri: Uri? = data.clipData?.getItemAt(i)?.uri
                            val file = getImageFromUri(imageUri)
                            file?.let {
                                selectedPaths.add(it.absolutePath)
                            }
                        }
                        imageAdapter.addSelectedImages(selectedPaths)
                    }
                    //If single image selected
                    else if (data?.data != null) {
                        val imageUri: Uri? = data.data
                        val file = getImageFromUri(imageUri)
                        file?.let {
                            selectedPaths.add(it.absolutePath)
                        }
                        imageAdapter.addSelectedImages(selectedPaths)
                    }
                }
            }

Deleting the Cache Directory

Once done with all your file operations, we need to clear the files from the cache directory. you can do this by using the below function.

fun deleteTempFiles(file: File = cacheDir): Boolean {
        if (file.isDirectory) {
            val files = file.listFiles()
            if (files != null) {
                for (f in files) {
                    if (f.isDirectory) {
                        deleteTempFiles(f)
                    } else {
                        f.delete()
                    }
                }
            }
        }
        return file.delete()
    }

Screenshots:

Source:

You can download the source in Github.

Leave a Reply

Your email address will not be published.