This article uses two ways to implement asynchronous loading of images in Compose

preface

Loading images asynchronously is a very common requirement in Android development. This article will walk you through this requirement. This paper will be divided into the following two aspects:

  1. Write your own function
  2. With the open source library

implementation

Write your own with Glide library

Glide open source library is basically the first choice for loading images on Android. Its easy to use API and powerful caching capabilities make this process very convenient. Naturally, it’s also available in Jetpack Compose.

Introduction of depend on

Add to build.gradle in the module

implementation 'com. Making. Bumptech. Glide: glide: 4.12.0'
annotationProcessor 'com. Making. Bumptech. Glide: the compiler: 4.12.0'
Copy the code

Write a function

How do I get Glide to load an image into the Compose component? For example, into(Target) is used to specify a custom Target, and the return value of mutableState

is used for Compose, for example, when an image is loaded, it automatically updates Compose. Let Glide load a local image for us first and then load the network image. We wrote the following function:

/** * Use Glide library to load network images *@author [FunnySaltyFish](https://funnysaltyfish.github.io)
 * @dateThe 2021-07-14 *@paramContext context reasonable context *@paramUrl String Url * of the loaded image@paramDefaultImageId Int Local image * loaded by default@returnMutableState<Bitmap? > Load complete (failure null) Bitmap -state */
fun loadImage(
    context: Context,
    url: String.@DrawableRes defaultImageId: Int = R.drawable.load_holder
): MutableState<Bitmap? > {val TAG = "LoadImage"
    valbitmapState: MutableState<Bitmap? > = mutableStateOf(null)

    // Add Headers to the request to increase the success rate of access
    val glideUrl = GlideUrl(url,LazyHeaders.Builder().addHeader("User-Agent"."Mozilla / 5.0 (Windows NT 10.0; Win64; X64) AppleWebKit/537.36 (KHTML like Gecko) Chrome/91.0.4472.124 Safari/ 537.36edg /91.0.864.67").build())

    // Load the local image first
    Glide.with(context)
        .asBitmap()
        .load(defaultImageId)
        .into(object : CustomTarget<Bitmap>() {
            override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>? {
                // Customize the Target to pass the image resources to bitmapState after loading
                bitmapState.value = resource
            }

            override fun onLoadCleared(placeholder: Drawable?).{}})// Then load the network image
    try {
        Glide.with(context)
            .asBitmap()
            .load(glideUrl)
            .into(object : CustomTarget<Bitmap>() {
                override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>? {
                    // Customize the Target to pass the image resources to bitmapState after loading
                    bitmapState.value = resource
                }

                override fun onLoadCleared(placeholder: Drawable?).{}})}catch (glideException: GlideException) {
        Log.d(TAG, "error: ${glideException.rootCauses}")}return bitmapState
}
Copy the code

Using the example

Here’s a simple example:

@Composable
fun LoadPicture(
    url : String
){

    val imageState = loadImage(
        context = LocalContext.current,
        url = url,
    )

    Card(modifier = Modifier
        .padding(4.dp)
        .clickable { }) {
        // If the image loads successfullyimageState.value? .let { Image( bitmap = it.asImageBitmap(), contentDescription ="",
                modifier = Modifier
                    .padding(4.dp)
                    .fillMaxWidth()
            )
        }
    }
}

/ /...

LazyColumn {
	val urls = arrayListOf<String>()
	for (i in 500.550.){urls.add("https://nyc3.digitaloceanspaces.com/food2fork/food2fork-static/featured_images/$i/featured_image.png")}
	itemsIndexed(urls){ _ , url -> LoadPicture(url = url)}
}
Copy the code

The effect is as shown in the figure below: Loading

To load P.S. : Don't forget to declare your network permissions!

With open source frameworks

In fact, Google is in itsDevelopment of the document, using an open source libraryAccompanist So we can use this as well

Simple example

implementation "Com. Google. Accompanist: accompanist - coil: 0.13.0"
Copy the code
/ * * *@author [FunnySaltyFish](https://funnysaltyfish.github.io)
 * @dateThe 2021-07-14 *@paramUrl loaded link */
@Composable
fun LoadPicture2(url:String){
    val painter = rememberCoilPainter(url)

    Box {
        Image(
            painter = painter,
            contentDescription = "".)when (painter.loadState) {
            is ImageLoadState.Loading -> {
                // Display a loading progress bar
                CircularProgressIndicator(Modifier.align(Alignment.Center))
            }
            is ImageLoadState.Error -> {
                // If something went wrong, you can write here
                Text(text = "An error occurred.", color = MaterialColors.RedA200)
            }
            else -> Text(text = "Unknown situation", color = MaterialColors.PurpleA400)
        }
    }
}
Copy the code

The Material colors in the above example come from the open source library CMaterialColors

The effect is as follows:

P.S. : If you want to see better loading, you can set the network type to a slower type in the emulator Settings

Some restrictions

Personally, this approach has the following problems:

  • Slide loading is not as smooth as Glide
  • There is a requirement for Kotlin edition, i.e. current (as of writing time)0.13.0Version must be usedkotlin1.5Or above, otherwise a compilation error will occur

reference

  • video

The end. If you are interested in my article, please visit my Github. IO interface guide!