Home > Enterprise >  Save image to internal storage using ActivityResultContracts.GetContent(). - (Kotlin/Java/Android)
Save image to internal storage using ActivityResultContracts.GetContent(). - (Kotlin/Java/Android)

Time:05-16

I'm new to file storage. My main goal is to take a picture with the camera, store it with good quality, then display it in an ImageView. I want to avoid asking for user permission (to use camera and external storage), and want to make this as simple as possible.

To take a picture, I'm using

val capturePicture = registerForActivityResult(ActivityResultContracts.TakePicture()) { it: Boolean -> }. I don't know how to get the bitmap from this function or if I should. To my understanding I should send the uri when calling capturePicture.launch(uri).

My question is if this is correct, also how do I get the URI, save it to internal storage (.openFileOutput()), then load it from internal storage.

I prefer the answer in Kotlin but Java is fine too. An explanation on how paths work in internal storage could be helpful too.

CodePudding user response:

I followed this medium article tutorial, adjusted it and added more functionality for my use case.

Saved images in the cache directory

To take the picture:

private val takeImageResult =
    registerForActivityResult(ActivityResultContracts.TakePicture()) { isSuccess ->
        if (isSuccess) {
            latestTmpUri?.let { uri ->
                loadPhotosFromInternalStorageIntoRecyclerView()
            }
        }
    }

To call take picture, save it, and get the uri:

private var latestTmpUri: Uri? = null
private fun takeImage() {
    lifecycleScope.launchWhenStarted {
        getTmpFileUri().let { uri ->
            latestTmpUri = uri
            takeImageResult.launch(uri)
        }
    }
}
private fun getTmpFileUri(): Uri {
    val tmpFile = File.createTempFile("tmp_image_file", ".jpg", requireActivity().cacheDir).apply {
        createNewFile()
        deleteOnExit()
    }
    return FileProvider.getUriForFile(requireActivity().applicationContext, "${BuildConfig.APPLICATION_ID}.provider", tmpFile)
}

To load the picture (loads the first picture in the list of pictures):

private fun loadPhotosFromInternalStorage(): List<InternalStoragePhoto> {
    val files = requireActivity().cacheDir.listFiles()
    return files?.filter {
        it.canRead() && it.isFile && it.name.endsWith(".jpg")
    }?.map {
        InternalStoragePhoto(it.name, it.toUri())
    } ?: listOf()
}
private fun displayImage() {
    Glide.with(photoImg.context)
        .load(loadPhotosFromInternalStorage()[0].uri)
        .into(photoImg)
}

Here's the custom object for the images:

data class InternalStoragePhoto(
    val name: String,
    val uri: Uri?
)

This is a simplified version of my code, here's the source code for the test app github repo

  • Related