Compose: Images From URLs

June 14, 2021

Fetch and show images from urls

Before We Start

We will be creating a simple app that can load an image from a remote url.

We’ll need to set up our project to use Jetpack Compose (currently you can only use the Compose API with the latest Android Studio Preview). In the app level build.gradle, we’ll need to enable compose and also declare its dependencies.

android {
    …

    buildFeatures {
        compose true
    }
    composeOptions {
        // This should be the same as your project’s kotlin version
        kotlinCompilerVersion "1.4.31"
        kotlinCompilerExtensionVersion "1.0.0-beta02"
    }

    …

}

dependencies {

    …

    implementation 'androidx.compose.ui:ui:1.0.0-beta02'

    // Tooling support (Previews, etc.)
    implementation 'androidx.compose.ui:ui-tooling:1.0.0-beta02'

    // Foundation (Border, Background, Box, Image, Scroll, shapes, animations, etc.)
    implementation 'androidx.compose.foundation:foundation:1.0.0-beta02'

    // Material Design
    implementation 'androidx.compose.material:material:1.0.0-beta02'

    // Material design icons
    implementation 'androidx.compose.material:material-icons-core:1.0.0-beta02'
    implementation 'androidx.compose.material:material-icons-extended:1.0.0-beta02'

    // Integration with activities
    implementation 'androidx.activity:activity-compose:1.3.0-alpha04'

    // Integration with ViewModels
    implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha03'

    // Integration with observables
    implementation 'androidx.compose.runtime:runtime-livedata:1.0.0-beta02'
    
    // Glide for composables
    implementation "com.google.accompanist:accompanist-glide:0.11.1"
    
    …

}

Try building the project and make sure it succeeds. If there is an error about the compiler version, make sure your com.android.tools.build:gradle is up to date.

Glide

Compose does not have a built in way of fetching and showing images from a url. We can use the Glide dependency found under the “Accompanist” repo by Google. Accompanist is a repo full of utils commonly needed during development, but not available at this time.

Remote Image

Let’s take a look at the RemoteImage composable we made using Glide and dissect it.

@Composable
fun RemoteImage(
    url: String,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
    alpha: Float = DefaultAlpha,
    colorFilter: ColorFilter? = null,
    onError: (message: String) -> Unit
) {
    val painter = rememberGlidePainter(url)

    Box {
        Image(
            painter = painter,
            contentDescription = contentDescription,
            modifier = modifier,
            alignment = alignment,
            contentScale = contentScale,
            alpha = alpha,
            colorFilter = colorFilter,
        )

        when (val loadState = painter.loadState) {
            is ImageLoadState.Loading -> {
                CircularProgressIndicator(Modifier.align(Alignment.Center))
            }
            is ImageLoadState.Error -> {
                onError(loadState.throwable?.message ?: "Failed to load the image")
            }
        }
    }
}

This code snippet is a modified code snippet found from the Glide website. The parameters of this composable are the exact same as the built in Image composable except painter has been replaced with url and an onError callback has been added.

val painter = rememberGlidePainter(url) does the heavy lifting for us by creating a LoadPainter that our composable will observe for changes. We can look at the loadState of the object and handle different states like ImageLoadState.Loading, ImageLoadState.Error, ImageLoadState.Success and ImageLoadState.Empty as we wish. In our code snippet we show a CircularProgressIndicator during the loading state, and we call the onError callback upon failure to notify the parent composable.

We can then pass the painter object to the Image composable we have defined so that upon successful completion, it will show the image. This works because we are observing the state of painter. When a composable observes the state of an object, it will recompose or redraw itself when the value of the object changes. It will only recompose the composables that depend on the value of the object. We will discuss states and recomposition in more detail in the future.

We can then call RemoteImage from any composable in the app. Here’s an example of how to use it

RemoteImage(
    url = "https://picsum.photos/300/300",
    contentDescription = ""
) { message ->
    // Show snackbar
}

Let's work together

Find out how we can help you grow.