I have a lot of pictures on a path , and i move picture to this path , loading pictures and displaying them on recyclerView take a lot of time , and i am using a fragment , when i change fragment and back to the one that display pictures , it take again a lot of time to load pictures .
any suggestion to load pictures fast ?
suspend fun getImages() = try {
val path = Environment.getExternalStorageDirectory()
.toString() + "Here folder path "
val directory = File(path)
val files = directory.listFiles()
if (files.isEmpty()) {
//
} else {
}
for (i in files.indices) {
println( files[i].name)
val myBitmap = BitmapFactory.decodeFile(files[i].getAbsolutePath())
var path = files[i].getAbsolutePath()
var fileName = files[i].name
var picture = Picture(myBitmap, path, fileName)
if (picture != null) {
listPictures.add(picture)
}
}
withContext(Dispatchers.Main){
myAdapter.notifyDataSetChanged()
}
} catch (e: Exception) {
}
```
Related
I save a png image to external storage using this block of code for sdk<=28
/**
* save image with this method if the sdk is 28 or lower
*/
private fun saveImageSdk28(fileName: String){
//declar the output stream variable outside of try/catch so that it can always be closed
var imageOutputStream: FileOutputStream? = null
var outputImageFile = getFile(fileName)
if (!outputImageFile.exists()) {
outputImageFile.createNewFile()
}
try {
imageOutputStream = FileOutputStream(outputImageFile)
encryptedBitmap.compress(Bitmap.CompressFormat.PNG, 100, imageOutputStream)
} catch (e: IOException) {
e.printStackTrace()
Timber.i(e.toString())
} finally {
if (imageOutputStream != null) {
imageOutputStream.flush()
imageOutputStream.close()
}
}
}
/**
* returns file from fileName
*/
fun getFile(fileName: String): File{
//open, or create the directory where the image will be stored
var directory = File(
Environment.getExternalStorageDirectory().toString() + "/AppNameOutput/"
)
if (!directory.exists()) {
directory.mkdir()
}
//create the file
var file: File = File(directory.absolutePath, fileName)
return file
}
and this code for when the sdk>28
/**
* save image with this method if the sdk is 29 or higher
*/
#RequiresApi(Build.VERSION_CODES.Q)
private fun saveImageSdk29(fileName: String){
val imageCollection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
val contentValues = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, "$fileName")
put(MediaStore.Images.Media.MIME_TYPE, "image/png")
put(MediaStore.Images.Media.WIDTH, encryptedBitmap.width)
put(MediaStore.Images.Media.HEIGHT, encryptedBitmap.height)
}
try{
val contentResolver = getApplication<Application>().contentResolver
contentResolver.insert(imageCollection, contentValues)?.also {uri->
contentResolver.openOutputStream(uri).use {outputStream ->
encryptedBitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
}
}
}catch (e: IOException){
e.printStackTrace()
}
}
The image sucsessfully saves on the users device and can be accesed through files, however, the user can't access these images through the gallery, or Images tab.
I solved it. Turns out you just need to wait a while and reboot the phone for the gallery to show your images.
I am building a photo vault where users can hide their photos.
I write the following code which traverses through all the directories (except the hidden one) and creates a report mentioning the number of images with directory name and file(images) path.
It works fine and does its job but the problem here is the amount of time it takes to execute.
I run it on my OnePlus 7T with 128 GB Storage and 52% used it takes almost 30-40 seconds to get all the images. That is an insane amount of time for a user to wait every time they want to add an image to the vault.
I want to know what optimization could be made here so that its speed gets optimized. I have tested other similar applications and they are doing it in a snap.
Please let me know if you can help.
#OptIn(ExperimentalTime::class)
private fun getFiles(): List<MyFileModel> {
val list = mutableListOf<MyFileModel>()
val time = measureTime {
Environment.getExternalStorageDirectory().listFiles()?.forEach {file->
if (file.isDirectory) {
openDirectory(file)
} else if (file.isImage) {
addImage(file)
Log.i(
TAG,
"getFiles: image: ${file.name}\nParent File: ${file.parentFile}\nParent: ${file.parent}"
)
}
}
}
Log.i(
TAG,
"getFiles: took ${time.inWholeHours}h : ${time.inWholeMinutes}m : ${time.inWholeSeconds}s"
)
map.keys.forEach {
Log.i(TAG, "getFiles: There are ${map[it]?.size} images in $it directory")
}
return listOf()
}
private fun addImage(file: File) {
val parentPath = file.parent ?: throw Exception("Could not add file as image. File: $file")
var folderName: String? = null
if (parentPath == FileUtils.ROOT_ADDRESS.path) {
folderName = "STORAGE"
//File is in the home directory
} else {
folderName = parentPath.substring(parentPath.lastIndexOf("/") + 1)
}
val files: MutableList<File>? = map[folderName]
if (files.isNullOrEmpty()) {
map[folderName] = mutableListOf(file)
} else {
files.addIfNotAlreadyAdded(file)
}
// Log.i(TAG, "addImage: map: $map")
}
//
private fun openDirectory(file: File) {
Log.i(TAG, "getFiles: FILE: ${file.absolutePath}")
if (file.isHidden) return
if (file.isImage) {
addImage(file)
return
}
if (file.isDirectory) {
file.listFiles()?.forEach {
Log.i(TAG, "openDirectory: file.listFiles().forEach : file: $it")
if (it.isImage) {
addImage(it)
}
if (it.isDirectory) {
openDirectory(it)
}
}
}
}
Here is the extensions function that checks if the file is an image or not.
val File.isImage: Boolean
get() {
val fileName = this.name
val lasIndexOfDot = fileName.lastIndexOf(".")
if (lasIndexOfDot == -1) {
//This means that the file got no extension
return false
}
val extension = fileName.substring(fileName.lastIndexOf(".") + 1).lowercase()
return extension.equals("png") ||
extension.equals("jpeg") ||
extension.equals("jpg") ||
extension.equals("gif")
}
Thank you :)
Finally, I was able to do that by implementing the Content Provider.
Going through all files and folders in the storage and then checking each file if it is an image or not and that too by looking at the file extension. It was a set of terrible ideas.
But in the end, this is how we learn. :)
I am facing issue with Bitmap image quality when getting a image file from internal storage and show on imageView. How to show image file with original quality using bitmap.
Here is my code
fun renderPdf(renderer: PdfRenderer, pagesBitmap: MutableList<Bitmap>, dir: File) {
try {
for (i in 0 until PAGE_COUNT) {
val document: PDDocument = PDDocument.load(dir)
val pdfRenderer = PDFRenderer(document)
val bim = pdfRenderer.renderImage(i, 3.5f, Bitmap.Config.ARGB_8888!!)
pagesBitmap.add(bim!!)
document.close()
// Save the render result to an image
val path: String =
Environment.getExternalStorageDirectory().toString() + "/.AOF/aof_$i.jpg"
val renderFile = File(path)
val fileOut = FileOutputStream(renderFile)
pagesBitmap[i].compress(Bitmap.CompressFormat.JPEG, 100, fileOut)
fileOut.close()
}
ivForm.pagesBitmap = pagesBitmapFiles
ivForm.displayPDFDocument()
renderer.close()
} catch (e: IOException) {
Log.e("PdfBox-Android-Sample", "Exception thrown while rendering file", e)
} finally {
callDocumentType()
}
}
I am using the third party library to open the Gallery and camera. I
have done that part. Now, when i select multiple image or single
image,got the array of URI from the third party lib. Now, i created the file
in app package folder and able to create it. But when i check under
app folder, the size of an image is 0 byte. I am saving the path also
on local db and later will upload it on server using multipart. Below
is my code.
To open the Gallery and camera
private fun openPicker() {
PhotoPickerFragment.newInstance(
multiple = true,
allowCamera = true,
maxSelection = 5,
theme = R.style.ChiliPhotoPicker_Light
).show(childFragmentManager, "picker")
}
got the selected image path URI and save path in to local db with createFile
override fun onImagesPicked(photos: ArrayList<Uri>) {
Log.e("TAG", "pic" + photos.joinToString(separator = "\n") { it.toString() })
fileList = ArrayList<File>()
try {
photos.forEachIndexed { index, e ->
println("$e at ${photos[index].path}")
val destinationFile: File = createImageFile()
fileList.add(destinationFile)
fileList.also {
// Get the file-name from the image-path
val destinationFilePath = it[index].absolutePath
val fileName =
destinationFilePath.substring(destinationFilePath.lastIndexOf("/") + 1)
val attachment = AttachSiteImage()
attachment.apply {
callLoggingId = callLoggingIdForAttachment
attachmentFileName = fileName
attachmentPath = destinationFilePath
}
attachImageviewModel?.addAttachFromApi(attachment)
}
}
Log.e("TAG", "Path->" + fileList.size)
} catch (ex: FileAlreadyExistsException) {
// sourceFile.delete()
cl_attachments_main_container.showSnackBar(
if (!ex.localizedMessage.isNullOrEmpty())
ex.localizedMessage
else
ex.stackTrace.toString(),
Snackbar.LENGTH_SHORT
)
} catch (ex: IOException) {
// sourceFile.delete()
cl_attachments_main_container.showSnackBar(
if (!ex.localizedMessage.isNullOrEmpty())
ex.localizedMessage
else
ex.stackTrace.toString(),
Snackbar.LENGTH_SHORT
)
}
}
Create the file where photos will be stored
#Throws(IOException::class)
private fun createImageFile(): File {
// Create an image file name
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
val storageDir: File? = requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES)
return File.createTempFile(
"${callLoggingIdForAttachment}_${timeStamp}_", /* prefix */
".jpg", /* suffix */
storageDir /* directory */
)
}
Here is the Library URL: https://github.com/ChiliLabs/ChiliPhotoPicker
Your createImageFile() function creates an empty file by returning a result of createTempFile, not an image file. You don't write anything to that empty file and use it as the attachment. And in
// Get the file-name from the image-path
val destinationFilePath = it[index].absolutePath
you don't use the image path as the comment says; you use the path of the empty file you just created.
The image file is given to you as Uri, e in
photos.forEachIndexed { index, e ->
but you ignore it except to log
println("$e at ${photos[index].path}")
So convert Uri to File
val destinationFile = File(e.path)
and work with that. Or copy it to the file created by createImageFile if that's what you want (answers there are for Java but IDEA/Android Studio can convert them to Kotlin for you).
I'm trying to create an application where i am required to add or delete an image simultaneously from image view and external storage. While doing the same, when I try adding the new image into the imageview using Uri, the old image keeps getting added again.
Here is my code
if (resultCode == Activity.RESULT_OK && requestCode == IMAGE_PICK_CODE_GALLERY) {
var selectedImage = data?.data
try {
val bitmap = MediaStore.Images.Media.getBitmap(context?.contentResolver,selectedImage)
if(bitmap!=null) {
val imageURI: String = getImageUri(context!!, bitmap)
}
private fun getImageUri(context: Context, inImage: Bitmap): String {
var fOut: OutputStream?
var path: String? = null
var fileName: String? = abc
var file: File? = null
file = File(
Environment.getExternalStorageDirectory().toString() + File.separator + "myDirectory",
"$fileName"
)
if (file.exists())
{
file.getCanonicalFile().delete()
if (file.exists())
{
context?.deleteFile(file.getName())
}
file.delete()
}
file.createNewFile() //If file already exists will do nothing
fOut = FileOutputStream(file)
inImage.compress(Bitmap.CompressFormat.JPEG, 40, fOut)
Glide.with(this).load(file).into(imageView!!)
fOut.flush()
fOut.close()
// path = MediaStore.Images.Media.insertImage(context.contentResolver,file.absolutePath,file.getName(),null);
} catch (ex: Exception) {
ex.printStackTrace()
}
return file.toString()
}
Glide caches your images, so probably you are loading a cached version of the old image.
As suggested in Glide's docs you should add a signature to handle cache invalidation:
Glide.with(yourFragment)
.load(yourFileDataModel)
.signature(new ObjectKey(yourVersionMetadata))
.into(yourImageView);