Load Image Faster Than Ever in Android

Shahadat Hossain Shaki
3 min readApr 5, 2022

Network image is the most common thing in android development. We need to show various images to the users. Sometimes those images are repeated, Meaning we are loading the same image every time Unless our app produces many images and the repeated image ratio is low. In that case, this blog is not for you.

Now come to the main point, We have an app that loads the same image most of the time. Most of us use Glide and Picasso library for loading the image from the network. In this blog, I will show examples from Picasso's library. Picasso and Glide both cache images to some extent. So that image can be loaded faster. We will use almost the same method to load images faster. We will store the loaded image in our local storage. Next time load the image from the local storage.

With this, We can load images within a blink of an eye and can save lots of users' bandwidth as we are not loading the image from the network. Yes, of course, you can also load the image from the network alongside with local load.

Getting into the code.

fun loadAndStoreImage(imageView: ImageView, url: String?) {
if (url == null || url.isEmpty()) {
return
}

GlobalScope.launch {
val file = getFileNameFromUrl(imageView.context, url)
if (file.length() != 0L) {
withContext(Dispatchers.Main) {
imageView.setImageURI(Uri.fromFile(file))
}
} else {
withContext(Dispatchers.Main) {
loadAndStoreImageFromPicasso(imageView, url)
}
}
}

}

Here we will use this method for loading the image from anywhere our app. This method will check if we have the file already stored in our local storage or not, If the file exists in local storage then show the file from local by converting the file into a Uri. Else load image from network and store into local storage.

fun loadAndStoreImageFromPicasso(imageView: ImageView?, url: String) {
try {
Picasso.get()
.load(url)
.placeholder(R.drawable.generic_placeholder)
.error(R.drawable.generic_placeholder)
.into(imageView, object : Callback {
override fun onSuccess() {
storeInLocalStorage(imageView!!, url)
}

override fun onError(e: java.lang.Exception) {
}
})
} catch (e: java.lang.Exception) {
}
}

Here we are loading images with Picasso and setting a callback for image loading completion.

fun storeInLocalStorage(imageView: ImageView, url: String) {

GlobalScope.launch {
try {
var bitmap: Bitmap = try {
val bitmapDrawable = imageView.drawable as RoundedDrawable
bitmapDrawable.sourceBitmap
} catch (e: java.lang.Exception) {
val bitmapDrawable = imageView.drawable as BitmapDrawable
bitmapDrawable.bitmap
}
val finalBitmap = bitmap
val file = getFileNameFromUrl(imageView.context, url)
if (!file.exists()) file.createNewFile()
val out = FileOutputStream(file)
finalBitmap.compress(Bitmap.CompressFormat.JPEG, 50, out)
out.flush()
out.close()
} catch (e: java.lang.Exception) {
e.printStackTrace()
Log.i(TAG, "storeInLocalStorage: " + e.localizedMessage)
}
}

}

Here getting the bitmap from the imageview and storing the bitmap into an image file.

fun getFileNameFromUrl(context: Context, url: String): File? {
var file: File? = null
file = try {
val root = ContextWrapper(context).getDir("Image", Context.MODE_PRIVATE).absolutePath
val myDir = File("$root/cache")
myDir.mkdirs()
val part = url.split("/").toTypedArray()
val part2 = part[part.size - 1].split("v=").toTypedArray()
val imageName = part2[0].replace("?", "")
File(myDir, imageName)
} catch (e: java.lang.Exception) {
return null
}
return file
}

My image URL: “https://mydomain.com/images/kB5lHNecgXEs8itCXq3T.jpeg?v=1576436”

Here we simply convert the URL into a file name, It may vary depending on your image URL design. Just take the image file name with the extension and create a file with it. You are done, with these 4 methods you can load images super fast for 2nd time.

I have another story for app content caching, With these 2 your app will be converted into an offline app from an online app.

--

--

Shahadat Hossain Shaki

Co-Founder and Android developer of Happihub. Loves to develop things.