Android Native - Load Images with Coil

dimitrilc 3 Tallied Votes 1K Views Share

Introduction

Coil is a popular image loading library for Kotlin-first Android projects. It is lightweight, fast and is super easy to use.

In this tutorial, we will learn how to use Coil to load images into our project.

Goals

At the end of the tutorial, you would have learned:

  1. How to load images with Coil.

Tools Required

  1. Android Studio. The version used in this tutorial is Arctic Fox 2020.3.1 Patch 4.

Prerequisite Knowledge

  1. Basic Android.

Project Setup

To follow along with the tutorial, perform the steps below:

  1. Create a new Android project with the default Empty Activity.

  2. Remove the Default “Hello World!” TextView.

  3. Add a new ImageView inside ConstraintLayout.

     <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:srcCompat="@tools:sample/avatars" />
  4. Add a new Button below ImageView with the code below.

     <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/load_image"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageView" />
  5. Add the <string> elements below to your strings.xml file.

     <string name="load_image">Random Image</string>
     <string name="circle">https://github.com/dmitrilc/DaniwebAndroidNativeCoil/raw/main/app/src/main/res/drawable/circle.png</string>
     <string name="rect">https://github.com/dmitrilc/DaniwebAndroidNativeCoil/raw/main/app/src/main/res/drawable/rect.png</string>
     <string name="triangle">https://github.com/dmitrilc/DaniwebAndroidNativeCoil/raw/main/app/src/main/res/drawable/triangle.png</string>
  6. The dependency to the Coil library to your module gradle.build file.

     implementation 'io.coil-kt:coil:1.4.0'
  7. Inside your AndroidManifest.xml, Add the android.permission.INTERNET permission before <application>, but after <manifest>.

     <uses-permission android:name="android.permission.INTERNET" />

Coil Packages

The Coil library includes a handful of artifacts. For the two base artifacts, certain variants contain a singleton ImageLoader instance and (Kotlin) extension functions for ImageView.

  1. io.coil-kt:coil-base: base artifact
  2. io.coil-kt:coil: base artifact and include singleton ImageLoader and ImageView extension functions.

Support for Jetpack Compose:

  1. io.coil-kt:coil-compose-base: supports Jetpack Compose.
  2. io.coil-kt:coil-compose: supports Jetpack Compose and includes singleton ImageLoader and ImageView extension functions.

Regarding the versions with the singleton ImageLoader, the library even went as far as to say that you should use the version without the singleton ImageLoader instead if you plan to inject the ImageLoader instance using dependency injection. If you are instantiating a custom ImageLoader instance and having a global singleton instance as well, then you might end up with multiple instances of ImageLoader at runtime.

For our tutorial, we will use the version with the singleton ImageLoader and ImageView extension functions.

Coil also includes artifacts for supporting gif, svg, and video formats.

  1. io.coil-kt:coil-gif: support for gif.
  2. io.coil-kt:coil-svg: support for svg.
  3. io.coil-kt:coil-video: support for video formats.

Primary Classes of Coil

Coil has two primary classes, ImageLoader and ImageRequest.

  1. ImageLoader: the service class that can submit ImageRequest objects.
  2. ImageRequest: a data object that provides information for a loading action, such as where to load images (with its data property) or the target ImageView to load the Image to (with its target property).

It is good to know about these two classes, but if you are using the io.coil-kt:coil artifact, then you barely have to write any boilerplate code at all. Loading an image is as simple as calling one of the load() extension functions on an ImageView reference.

Load images with ImageView extension functions

The simplest way to get an image is to use the ImageView extension functions.

  1. In MainActivity#onCreate(), get the Button reference.

     val button = findViewById<Button>(R.id.button)
  2. Then, get the ImageView reference.

     val imageView = findViewById<ImageView>(R.id.imageView)
  3. Finally, bind the Button to a load() action. The code below will randomly load one of three images from this project’s github repository.

     button.setOnClickListener {
        when(Random.nextInt(0, 3)){
            0 -> imageView.load(getString(R.string.rect))
            1 -> imageView.load(getString(R.string.triangle))
            2 -> imageView.load(getString(R.string.circle))
        }
     }

Load images with ImageLoader

This is the longer route and is unnecessary for our project, but I will still show it as reference. In onCreate(), also add the multi-line comment below.

/** Long way to load an image
val imageLoader = applicationContext.imageLoader
val request = ImageRequest.Builder(applicationContext)
   .data(getString(R.string.rect))
   .target(imageView)
   .build()

imageLoader.enqueue(request)
**/

Run the App

We are now ready to run our App. In the gif below, I have also included the Profiler output to demonstrate how resources were used when loading the image.

Coil.gif

Solution Code

MainActivity.kt

package com.example.daniwebandroidnativecoil

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.ImageView
import coil.Coil
import coil.imageLoader
import coil.load
import coil.request.ImageRequest
import coil.util.CoilUtils
import okhttp3.OkHttpClient
import kotlin.random.Random

class MainActivity : AppCompatActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.activity_main)

       val button = findViewById<Button>(R.id.button)
       val imageView = findViewById<ImageView>(R.id.imageView)

       button.setOnClickListener {
           when(Random.nextInt(0, 3)){
               0 -> imageView.load(getString(R.string.rect))
               1 -> imageView.load(getString(R.string.triangle))
               2 -> imageView.load(getString(R.string.circle))
           }
       }

       /** Long way to load an image
       val imageLoader = applicationContext.imageLoader
       val request = ImageRequest.Builder(applicationContext)
           .data(getString(R.string.rect))
           .target(imageView)
           .build()

       imageLoader.enqueue(request)
       **/
   }

}

activity_main.xml

<?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="wrap_content"
       android:layout_height="wrap_content"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toTopOf="parent"
       tools:srcCompat="@tools:sample/avatars" />

   <Button
       android:id="@+id/button"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="@string/load_image"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toBottomOf="@+id/imageView" />
</androidx.constraintlayout.widget.ConstraintLayout>

strings.xml

<resources>
   <string name="app_name">Daniweb Android Native Coil</string>
   <string name="load_image">Random Image</string>
   <string name="circle">https://github.com/dmitrilc/DaniwebAndroidNativeCoil/raw/main/app/src/main/res/drawable/circle.png</string>
   <string name="rect">https://github.com/dmitrilc/DaniwebAndroidNativeCoil/raw/main/app/src/main/res/drawable/rect.png</string>
   <string name="triangle">https://github.com/dmitrilc/DaniwebAndroidNativeCoil/raw/main/app/src/main/res/drawable/triangle.png</string>
</resources>

build.gradle

plugins {
   id 'com.android.application'
   id 'kotlin-android'
}

android {
   compileSdk 31

   defaultConfig {
       applicationId "com.example.daniwebandroidnativecoil"
       minSdk 21
       targetSdk 31
       versionCode 1
       versionName "1.0"

       testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
   }

   buildTypes {
       release {
           minifyEnabled false
           proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
       }
   }
   compileOptions {
       sourceCompatibility JavaVersion.VERSION_1_8
       targetCompatibility JavaVersion.VERSION_1_8
   }
   kotlinOptions {
       jvmTarget = '1.8'
   }
}

dependencies {

   implementation 'androidx.core:core-ktx:1.7.0'
   implementation 'androidx.appcompat:appcompat:1.4.0'
   implementation 'com.google.android.material:material:1.4.0'
   implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
   implementation 'io.coil-kt:coil:1.4.0'
   testImplementation 'junit:junit:4.+'
   androidTestImplementation 'androidx.test.ext:junit:1.1.3'
   androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

Summary

We have learned how to use Coil to load images. The full project code can be found at https://github.com/dmitrilc/DaniwebAndroidNativeCoil

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.