In this post, we will be learning about android Glide library in Kotlin with example. We will see how to use glide library in any android app, different options available etc.
Getting Started
Glide is fast and efficient image loading library for android. Using android Glide library in Kotlin, you can –
- download, decode and display images, videos or animated GIFs
- cache, resize downloaded images
- show placeholder while loading image
- show pre-defined images when there is any error while downloading image
- apply animation while loading image
Primary focus of glide library is – making scrolling of any kind of image list as smooth and fast as possible.
In this tutorial, we will learn –
- Basic setup for Glide Library
- Load image into imageView
- Show placeholder while loading image
- Using RequestOptions for multiple downloads into multiple views
- Show error image if unsuccessful download
- Resize downloaded image
- Showing fallback image
- Using CustomTarget in imageView
- Using RequestListener into imageView
- Using Glide With RecyclerView
Let’s start implementing android glide library in Kotlin with example.
Creating New Project
Follow steps below to create any android project in Kotlin –
Step | Description |
---|---|
1. | Open Android Studio (Ignore if already done). |
2. | Go to File => New => New Project. This will open a new window. Then, under Phone and Tablet section, select Empty Activity. Then, click Next. |
3. | In next screen, select project name as GlideLibrary. Then, fill other required details. |
4. | Then, clicking on Finish button creates new project. |
Newbie in Android ?
Some very important concepts (Recommended to learn before you move ahead)
Before we move ahead, we need to setup for viewBinding to access widget in Kotlin file without using findViewById() method.
Setup ViewBinding
Add viewBinding = true in app/build.gradle file.
android { // OTHER CODE... buildFeatures { viewBinding true } }
Now, set content in activity using view binding.
Open MainActivity.kt file and write below code in it.
class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) val view = binding.root setContentView(view) } }
Now, we can access view in Kotlin file without using findViewById() method.
Add Gradle in app/build.gradle file
After creating project, you need to add gradle for Glide library in your project. So, copy below line and add it in your app/build.gradle file.
implementation 'com.github.bumptech.glide:glide:4.12.0'
After adding above line, click on Sync button shown at top-right of IDE.
Add Internet Permission
Since we are going to load image using url. We need to add internet permission in our app. So, add below line into your AndroidManifest.xml file.
<uses-permission android:name="android.permission.INTERNET"/>
Above two steps (add gradle for Glide and internet permission) are minimum requirement for Glide to start working. Now, we can use glide for different purposes. For example, to load image into imageView, use it in recyclerView etc. We will see them one by one –
Load image into ImageView
At first, we will load image into imageView. There are two steps for this action –
- Prepare XML Layout
- Write code to download and load image
-
Prepare XML Layout
Goto src/main/res/layout folder and open activity_main.xml file. Then, add imageView into it. You can also copy/paste below code in your activity_main.xml file.
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <ImageView android:id="@+id/imageView" android:layout_width="120dp" android:layout_height="120dp" android:contentDescription="@string/image_description" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
Here, You need to add a string resource in res/values/strings.xml file –
<string name="image_description">Image Description</string>
-
Write Code to Download Image
To download and load any image into imageView, we can use below code –
Glide.with(this) .load("IMAGE_URL") .into(imageView)
So, goto src/main/java/com.tutorialwing.glidelibrary folder and open MainActivity.kt file. Then, add below code into it.
package com.tutorialwing.glidelibrary import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import com.bumptech.glide.Glide import com.tutorialwing.glidelibrary.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) val view = binding.root setContentView(view) // Load image into imageView val imageUrl = "http://goo.gl/gEgYUd" Glide.with(this) .load(imageUrl) .into(binding.imageView) } }
-
After this, build and run your project. You will see screen like below –
Bingo!
We have successfully downloaded and loaded image into imageView using Glide Library in Kotlin.
Advance Concepts in Glide Library
Now, we do other operations as well using android Glide library in Kotlin With Example. We will see them one by one.
Show Placeholder While Image is Being Loaded
What if you wish to show placeholder while image is being loaded ?
You can do it as below –
.placeholder("PLACEHOLDER IMAGE URL")
Follow steps below to do it in our project –
-
We will add a button to start loading image. This is being done so that placeholder is clearly shown while image is being downloaded.
Goto src/main/res/layout folder and open activity_main.xml file. Then, add button into it. Also, modified some attributes of imageView to adjust ui accordingly.
Code for this action is –
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <ImageView android:id="@+id/imageView" android:layout_width="120dp" android:layout_height="120dp" android:contentDescription="@string/image_description" app:layout_constraintBottom_toTopOf="@+id/load_image" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/load_image" android:layout_width="wrap_content" android:layout_height="0dp" android:layout_marginBottom="201dp" android:text="@string/start_loading" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
Also, open res/values/strings.xml file. Then, add string resource, start_loading, in it as shown below –
<string name="start_loading">Start Loading</string>
-
Now, we write code in MainActivity.kt file to start image loading when button is clicked.
So, open MainActivity.kt file. Then, write below code in it –
package com.tutorialwing.glidelibrary import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import com.bumptech.glide.Glide import com.tutorialwing.glidelibrary.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) val view = binding.root setContentView(view) binding.loadImage.setOnClickListener { startLoadingImage() } } private fun startLoadingImage() { val imageUrl = "http://goo.gl/gEgYUd" Glide.with(this) .load(imageUrl) .placeholder(R.mipmap.ic_launcher) .into(binding.imageView) } }
Here, we have defined a method startLoadingImage() that is called when button is clicked. In this method, we have written code
– to load image into imageView
– show placeholder image, ic_launcher, while image is being downloaded.
Show Error Image
We can use .error(“IMAGE URL”) to show error placeholder.
Error drawables are shown if
- request fails permanently.
- Requested url/model is null and fallback url is not set.
In our app, we can set error placeholder as below
- Open src/main/java/com.tutorialwing.glidelibrary.MainActivity file and copy/paste below code into it.
package com.tutorialwing.glidelibrary import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import com.bumptech.glide.Glide import com.tutorialwing.glidelibrary.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) val view = binding.root setContentView(view) binding.loadImage.setOnClickListener { startLoadingImage() } } private fun startLoadingImage() { val imageUrl = "http://goo.gl/gEgYUd" val inCorrectImageUrl = "http://goo.gl/gEgYUdXXXX" Glide.with(this) .load(inCorrectImageUrl) .placeholder(R.mipmap.ic_launcher) .error(R.mipmap.ic_launcher_round) .into(binding.imageView) } }
Here, ic_launcher_round is loaded into imageView becuase we are trying to load image from incorrect url.
Show Fallback Image
We can use .fallback(“IMAGE URL”) to show fallback placeholder.
Fallback placeholder is used when
- requested url/model is null.
In our app, we can set fallback placeholder as below
- Open src/main/java/com.tutorialwing.glidelibrary.MainActivity file and copy/paste below code into it.
package com.tutorialwing.glidelibrary import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import com.bumptech.glide.Glide import com.tutorialwing.glidelibrary.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) val view = binding.root setContentView(view) binding.loadImage.setOnClickListener { startLoadingImage() } } private fun startLoadingImage() { val imageUrl = "http://goo.gl/gEgYUd" val inCorrectImageUrl = "http://goo.gl/gEgYUdXXXX" Glide.with(this) .load(inCorrectImageUrl) .placeholder(R.mipmap.ic_launcher) .error(R.mipmap.ic_launcher_round) .fallback(android.R.drawable.ic_menu_camera) .into(binding.imageView) } }
Applying Transformation Using Glide
If you want to apply transformation i.e. crop, apply filter to bitmap, you can do so using Glide library. There are several in-built transformations in glide –
- CenterCrop
- FitCenter
- CircleCrop
Example –
Glide.with(this) .load(correctUrl) .placeholder(R.mipmap.ic_launcher) .error(R.drawable.ic_launcher_background) .fallback(android.R.drawable.ic_menu_camera) .circleCrop() .into(imageView)
Here, we have applied circleCrop transition using .circleCrop(). Visit official site to know more about transition in glide.
Applying Transition Using Glide
We can also apply transition using glide library. It shows how glide should apply transition from a placeholder to newly loaded image , or from a thumbnail to full size image. Similarly, we can apply other transitions.
We can apply many transition using glide. Here, we just look into an example –
- Open src/main/java/com.tutorialwing.glidelibrary.MainActivity file and copy/paste below code into it.
package com.tutorialwing.glidelibrary import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import com.bumptech.glide.Glide import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade import com.bumptech.glide.request.transition.DrawableCrossFadeFactory import com.tutorialwing.glidelibrary.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) val view = binding.root setContentView(view) binding.loadImage.setOnClickListener { startLoadingImage() } } private fun startLoadingImage() { val imageUrl = "http://goo.gl/gEgYUd" val factory = DrawableCrossFadeFactory.Builder().setCrossFadeEnabled(true).build() Glide.with(this) .load(imageUrl) .placeholder(R.mipmap.ic_launcher) .error(R.drawable.ic_launcher_background) .fallback(android.R.drawable.ic_menu_camera) .circleCrop() .transition(withCrossFade(factory)) .into(binding.imageView) } }
Notice .transition(withCrossFade(factory)) line. We applied cross fade transition in glide using this method.
Transition acts within context of single request, NOT across multiple requests.
Visit official site to know more about transition in Glide.
Resizing Image
If you want to resize downloaded image and then load it into view, you can do so using .override(200, 200) method.
As of now, our MainActivity.kt file contains –
Glide.with(this) .load(correctUrl) .placeholder(R.mipmap.ic_launcher) .error(R.drawable.ic_launcher_background) .fallback(android.R.drawable.ic_menu_camera) .circleCrop() .override(200, 200) // Dimensions in pixel... .transition(withCrossFade(factory)) .diskCacheStrategy(DiskCacheStrategy.ALL) .into(imageView)
Notice .override(200, 200) method. We have passed height and width as 200 in pixel.
Caching in Glide
Glide performs multi-stage checking before it actually downloads image from remote url. It checks multiple layer –
- Active Resources – Is this image displayed in another View right now?
- Memory Cache – Was this image recently loaded and still in memory?
- Resource – Has this image been decoded, transformed, and written to the disk cache before?
- Data – Was the data this image was obtained from written to the disk cache before?
First two steps checks if image is in memory, if yes, it returns image immediately. Last two steps checks if memory is in disk. If yes, it returns immediately.
If all the four steps fails i.e. if image is neither found in memory nor in disk, Glide sends request to fetch image from remote url.
Glide provides different methods to configure how Glide should manage caching. Whether it should support only disk caching, or it should load only from cache etc.
Some of common methods are –
-
Disk Cache Strategies
Using diskCacheStrategy method, we apply disk caching. Value passed in method defines how disk caching is configured. For example,
- DiskCacheStrategy.ALL – It caches remote data with both DATA and RESOURCE, and local data with RESOURCE only.
- DiskCacheStrategy.AUTOMATIC – It is set by default. It tries to choose strategy using DataFetcher and EncodeStrategy.
- DiskCacheStrategy.DATA – Writes retrieved data directly to disk cache before it is decoded.
- DiskCacheStrategy.NONE – It does not save data to cache.
- DiskCacheStrategy.RESOURCE – It writes data to disk after it is decoded.
We can apply disk caching as –
Glide.with(CONTEXT) .load(URL) .diskCacheStrategy(DiskCacheStrategy.ALL) .into(imageView)
-
Loading only from cache
Using .onlyRetrieveFromCache(true), we can configure to fail loading image if it is not present in cache.
We can apply load only from cache as –
Glide.with(CONTEXT) .load(URL) .onlyRetrieveFromCache(true) .into(imageView);
-
Skip Caching
If you want to skip caching (memory or disk or both), you can do so as below
Skip Memory caching –
Glide.with(CONTEXT) .load(URL) .skipMemoryCache(true) .into(view);
Skip Disk caching –
Glide.with(CONTEXT) .load(URL) .diskCacheStrategy(DiskCacheStrategy.NONE) .into(view);
Skip Both(Memory or Disk) caching –
Glide.with(CONTEXT) .load(URL) .diskCacheStrategy(DiskCacheStrategy.NONE) .skipMemoryCache(true) .into(view);
In our app, we have just applied disk caching. As of now, our MainActivity.kt file contains below code –
package com.tutorialwing.glidelibrary import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import com.bumptech.glide.Glide import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade import com.bumptech.glide.request.transition.DrawableCrossFadeFactory import com.tutorialwing.glidelibrary.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) val view = binding.root setContentView(view) binding.loadImage.setOnClickListener { startLoadingImage() } } private fun startLoadingImage() { val imageUrl = "http://goo.gl/gEgYUd" val factory = DrawableCrossFadeFactory.Builder().setCrossFadeEnabled(true).build() Glide.with(this) .load(imageUrl) .placeholder(R.mipmap.ic_launcher) .error(R.drawable.ic_launcher_background) .fallback(android.R.drawable.ic_menu_camera) .circleCrop() .transition(withCrossFade(factory)) .diskCacheStrategy(DiskCacheStrategy.ALL) .into(binding.imageView) } }
Using CustomTargets in Glide
If you want to download image as bitmap, then set it into View, you can do so using CustomTarget. Open src/main/java/com.tutorialwing.glidelibrary.MainActivity file and copy/paste below code into it.
package com.tutorialwing.glidelibrary import android.graphics.Bitmap import android.graphics.drawable.Drawable import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import com.bumptech.glide.Glide import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade import com.bumptech.glide.request.target.CustomTarget import com.bumptech.glide.request.transition.DrawableCrossFadeFactory import com.bumptech.glide.request.transition.Transition import com.tutorialwing.glidelibrary.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) val view = binding.root setContentView(view) binding.loadImage.setOnClickListener { startLoadingImage() } } private fun startLoadingImage() { Glide.with(this) .asBitmap() .load("https://github.com/bumptech/glide/blob/master/static/glide_logo.png?raw=true") .into(object : CustomTarget<Bitmap?>() { override fun onResourceReady( resource: Bitmap, transition: Transition<in Bitmap?>? ) { binding.imageView.setImageBitmap(resource) } override fun onLoadCleared(placeholder: Drawable?) { TODO("Not yet implemented") } }) } }
Here, we have used CustomTarget to load image as bitmap. Then, on successful load, we have set into imageView.
Using RequestListener in Glide
Till now, we have see how to use android library in kotlin, how to perform various options like showing placeholder, error image, fallback image etc. using glide library in android project. Now, we will see how to use RequestListener to download image and load it in view. Open src/main/java/com.tutorialwing.glidelibrary.MainActivity file and copy/paste below code into it.
package com.tutorialwing.glidelibrary import android.graphics.Bitmap import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.bumptech.glide.Glide import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.engine.GlideException import com.bumptech.glide.request.RequestListener import com.tutorialwing.glidelibrary.databinding.ActivityMainBinding import com.bumptech.glide.request.target.Target class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) val view = binding.root setContentView(view) binding.loadImage.setOnClickListener { startLoadingImage() } } private fun startLoadingImage() { Glide.with(this) .asBitmap() .load("https://github.com/bumptech/glide/blob/master/static/glide_logo.png?raw=true") .listener(object : RequestListener<Bitmap> { override fun onLoadFailed( e: GlideException?, model: Any?, target: Target<Bitmap>?, isFirstResource: Boolean ): Boolean { loadErrorImage() return false } override fun onResourceReady( resource: Bitmap?, model: Any?, target: Target<Bitmap>?, dataSource: DataSource?, isFirstResource: Boolean ): Boolean { loadImageBitmap(resource) return false } }).submit() } private fun loadErrorImage() { runOnUiThread { binding.imageView.setImageResource(R.mipmap.ic_launcher_round) } } private fun loadImageBitmap(bitmap: Bitmap?) { runOnUiThread { binding.imageView.setImageBitmap(bitmap) } } }
Here, we have used RequestListener to download image. Then, we set it into imageView.
Note: We need to set image inside runOnUiThread. Otherwise, you will get error like below –
com.bumptech.glide.load.engine.CallbackException: Unexpected exception thrown by non-Glide code .......... com.bumptech.glide.load.engine.executor.GlideExecutor$DefaultThreadFactory$1.run(GlideExecutor.java:393) Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Using RequestOptions in Glide
If we need to use same configuration in your app, we can do so using RequestOption. Follow steps below to see how do we use RequestOption.
- Modify xml layout to show multiple views
- Write code in Kotlin file to download image using same configuration.
Modify XML layout
Open src/main/res/layout/activity_main.xml file. Then copy/paste below code into it.
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <ImageButton android:id="@+id/imageView" android:layout_width="120dp" android:layout_height="120dp" android:contentDescription="@string/image_description" app:layout_constraintBottom_toTopOf="@+id/load_image" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.178" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ImageButton android:id="@+id/imageView2" android:layout_width="120dp" android:layout_height="120dp" android:contentDescription="@string/image_description" app:layout_constraintBottom_toTopOf="@+id/load_image" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/imageView" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/load_image" android:layout_width="wrap_content" android:layout_height="0dp" android:layout_marginBottom="201dp" android:text="@string/start_loading" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
Modify Kotlin file
Open src/main/java/com.tutorialwing.glidelibrary.MainActivity file and copy/paste below code into it.
package com.tutorialwing.glidelibrary import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.bumptech.glide.Glide import com.bumptech.glide.request.RequestOptions import com.tutorialwing.glidelibrary.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) val view = binding.root setContentView(view) binding.loadImage.setOnClickListener { startLoadingImage() } } private fun startLoadingImage() { val sharedOptions: RequestOptions = RequestOptions() .placeholder(R.mipmap.ic_launcher) .circleCrop() Glide.with(this) .load("http://goo.gl/gEgYUd") .apply(sharedOptions) .into(binding.imageView) Glide.with(this) .load("https://github.com/bumptech/glide/blob/master/static/glide_logo.png?raw=true") .apply(sharedOptions) .into(binding.imageView2) } }
Now, run your app. It should download image with same settings and load them into corresponding imageView.
We would get output as below –
What Next?
Take a break!
Post is getting too long. So, we are breaking it into two parts.
In this post, we learnt about android Glide library in Kotlin with example.
In next post, we will learn about Using Glide library with RecyclerView. We will create a beautiful gallery using Glide library.
That’s end of our tutorial on android glide library in Kotlin With Example.
You must be logged in to post a comment.