Loading images for Jetpack Compose using Glide, Coil, and Fresco

Blog Infos
Author
Published
Topics
, ,
Author
Published
Posted by: Jeawoong Eum

A new modern UI toolkit Jetpack Compose has been announced by Google over a year ago, and finally, it has been released 1.0 stable in July. Also many kinds of companies like Twitter, lyft, Square already have been adapted the Jetpack Compose in their production levels because it is very intuitive, powerful, and simplifies the entire UI structure if we use it well. This new paradigm of the UI structure will change a lot of things in our future, also we have to do more efforts to migrate the previous UI-related things like loading images from Url.

Loading and drawing images for Jetpack Compose

When Google announced Jetpack Compose 1.0.0-alpha01, I was wondered that how should we migrate all of the previous UI-related systems to Jetpack Compose projects? Simply fetching images from an Url (network) and drawing on the Image composable would require a completely different process from before. At that time, accompanist by Chris Banes has been released and I was got many inspired by the library. The library supported Coil (Glide was supported later), but I wanted to use and provide as many as possible options to choose image-loading libraries. Because migrating the entire image loading systems (e.g., from Glide to Coil) could give a hundred of pain to developers. So Landscapist was created to support many options like Glide, Coil, and Fresco for Jetpack Compose.

Landscapist

Landscapist is an image loading library for Jetpack Compose. There are three options; Glide, Coil, and Fresco. So we can choose by our preference. This library also supports loading animations like shimmer effect and circular reveal. If you want to look up more usages of this library, you can reference demo projects that using Landscapist for drawing images.

GlideImage

We can load and draw images from an Url using a GlideImage composable function like the below. That’s quite simple.

GlideImage(
imageModel = poster.poster
)

We also can give basic attributes same as the Image composable like contentScale and modifier.

GlideImage(
imageModel = poster.poster,
contentScale = ContentScale.Crop,
modifier = Modifier
)

If we want to show a placeholder (loading) and an error image based on the fetching state, we can use the placeHolder and error attributes like the below.

GlideImage(
imageModel = imageUrl,
// Crop, Fit, Inside, FillHeight, FillWidth, None
contentScale = ContentScale.Crop,
// shows an image with a circular revealed animation.
circularRevealedEnabled = true,
// shows a placeholder ImageBitmap when loading.
placeHolder = ImageBitmap.imageResource(R.drawable.placeholder),
// shows an error ImageBitmap when the request failed.
error = ImageBitmap.imageResource(R.drawable.error)
)
Different Composable based on requesting states

Sometimes we need to implement different UI based on requesting states. Basically, we can implement different composables based on the loading/success/error states. The below example shows an indicator when the requesting state is loading, and it will show a Text composable when it goes fail. If the request succeeds, it will show a loaded image.

If we want to custom your success composable, we can also custom the success UI result like the below. The success lambda passes a state of the requesting, and we can get an ImageBitmap from the state instance.

LocalGlideRequestBuilder

CompositionLocal is one of the most used concepts in the Jetpack Compose, and the official Android reference describes it like the below.

Compose passes data through the composition tree explicitly through means of parameters to composable functions. This is often times the simplest and best way to have data flow through the tree. CompositionLocals can be used as an implicit way to have data flow through a composition.

Landscapist also supports the CompositionLocal for providing like RequestBuilder (the backbone of the request in Glide) in the composable data flow.

CoilImage

Coil is almost the same as the Glide, it uses CoilImage instead of the GlideImage.

Also we can give many kinds of custom attributes like Glide.

LocalCoilImageLoader

Also supports the CompositionLocal for providing like ImageLoader in the composable hierarchy.

FrescoImage

Fresco is a little different from the above, we should initialize an image pipeline before to use. If we need to fetch images from the network, recommend using OkHttpImagePipelineConfigFactory.
By using an ImagePipelineConfig, we can customize caching, networking, and thread pool strategies. Here are more references related to the pipeline config.

class App : Application() {
override fun onCreate() {
super.onCreate()
val pipelineConfig =
OkHttpImagePipelineConfigFactory
.newBuilder(this, OkHttpClient.Builder().build())
.setDiskCacheEnabled(true)
.setDownsampleEnabled(true)
.setResizeAndRotateEnabledForNetwork(true)
.build()
Fresco.initialize(this, pipelineConfig)
}
}
view raw FrescoApp.kt hosted with ❤ by GitHub

Also other things are almost the same as the above libraries.

FrescoImage(
imageUrl = stringImageUrl,
// Crop, Fit, Inside, FillHeight, FillWidth, None
contentScale = ContentScale.Crop,
// shows an image with a circular revealed animation.
circularRevealedEnabled = true,
// shows a placeholder ImageBitmap when loading.
placeHolder = ImageBitmap.imageResource(R.drawable.placeholder),
// shows an error ImageBitmap when the request failed.
error = ImageBitmap.imageResource(R.drawable.error)
)
view raw FrescoImage.kt hosted with ❤ by GitHub

Job Offers

Job Offers


    Developer (m/w/d) Backend/ Mobile

    Payback GmbH
    Cologne, Germany
    • Full Time
    apply now

    Senior Compiler Engineer C++/LLVM – Munich

    Guardsquare
    Munich
    • Full Time
    apply now

    Android Engineer (m/f/x)

    Scalable Capital GmbH
    München, Berlin, remote
    • Full Time
    apply now
Load more listings

OUR VIDEO RECOMMENDATION

Jobs

Shimmer effect

Landscapist supports shimmer effect when loading images from network, and we can implement it using a ShimmerParams. The below example uses CoilImage but we can also apply the ShimmerParams for GlideImage and FrescoImage.

CoilImage(
imageModel = poster.poster,
modifier = modifier,
// shows a shimmering effect when loading an image.
shimmerParams = ShimmerParams(
baseColor = MaterialTheme.colors.background,
highlightColor = shimmerHighLight,
durationMillis = 350,
dropOff = 0.65f,
tilt = 20f
),
// shows an error text message when request failed.
failure = {
Text(text = "image request failed.")
})

We can customize the details of the ShimmerParam using baseColorhighlightColordurationMillisdropOff, and tilt.

Circular reveal animation

Landscapist supports circular reveal animation when showing images. This can be implemented very simply by giving the circularRevealedEnabledattribute as true.

FrescoImage(
imageUrl = stringImageUrl,
// Crop, Fit, Inside, FillHeight, FillWidth, None
contentScale = ContentScale.Crop,
// shows an image with a circular revealed animation.
circularRevealedEnabled = true,
// shows a placeholder ImageBitmap when loading.
placeHolder = ImageBitmap.imageResource(R.drawable.placeholder),
// shows an error ImageBitmap when the request failed.
error = ImageBitmap.imageResource(R.drawable.error)
)
CircularRevealedImage

We can use CircularRevealedImage composable regardless of image loading libraries (Glide, Coil, Fresco) and we can implement circular reveal animation using our drawable resource image.

CircularRevealedImage(
bitmap = ImageBitmap.imageResource(R.drawable.flower),
contentDescription = null,
circularRevealedEnabled = true,
circularRevealedDuration = 350
)

We should set the circularRevealedEnabled as true if we want to apply circular reveal animation, also we can change the duration of the animation using circularRevealedDuration attribute.

Palette

Landscapist supports palette APIs for extracting color profiles from images. Basically, we should use BitmapPalette to extract major colors from images like the below. And we can reference color types here.

var palette by remember { mutableStateOf<Palette?>(null) }
GlideImage( // CoilImage, FrescoImage also can be used.
imageModel = poster?.poster!!,
bitmapPalette = BitmapPalette {
palette = it
}
)
Crossfade(
targetState = palette,
modifier = Modifier
.padding(horizontal = 8.dp)
.size(45.dp)
) {
Box(
modifier = Modifier
.background(color = Color(it?.lightVibrantSwatch?.rgb ?: 0))
.fillMaxSize()
)
}
view raw Palette.kt hosted with ❤ by GitHub

We can customize more options using like interceptor and paletteLoadListener .

var palette by remember { mutableStateOf<Palette?>(null) }
GlideImage(
imageModel = poster?.poster!!,
modifier = Modifier
.aspectRatio(0.8f),
bitmapPalette = BitmapPalette(
imageModel = poster.poster,
useCache = true,
interceptor = {
it.addFilter { rgb, hsl ->
// here edit to add the filter colors.
false
}
},
paletteLoadedListener = {
palette = it
}
)
)
Conclusion

In this post, we looked around how to load and draw images for Jetpack Compose using Landscapist. Very thankfully, this library has been used by many global companies including Twitter. This journey started from the Jetpack Compose 1.0.0-alpha and now it has been released more than 30 times until reaches the Jetpack Compose 1.0 stable. Luckily, I got a lot of inspired and helped from accompanist (Thank you, Chris Banes! and thanks for all the Google Compose, Android Team!), and this long journey seems to just get started. ?

GitHub – skydoves/Landscapist: ? Jetpack Compose image loading library which can fetch and display…

? Jetpack Compose image loading library which can fetch and display network images using Glide, Coil, and Fresco. …

github.com

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog

How to animate BottomSheet content using Jetpack Compose

Early this year I started a new pet project for listening to random radio…
READ MORE
blog
Yes! You heard it right. We’ll try to understand the complete OTP (one time…
READ MORE
blog
The dictionary defines the term side-effect as an undesirable effect. While this applies to…
READ MORE
blog
Drag and Drop reordering in Recyclerview can be achieved with ItemTouchHelper (checkout implementation reference).…
READ MORE
Menu