Coil — khái niệm, thuật ngữ chính và ImageLoader trong Android

Tác giả: IT Sectr Đã đăng: 2026-05-05 Thời gian đọc: 9 phút

Coil là một thư viện tải hình ảnh cho Android, được viết bằng Kotlin và xây dựng trên coroutines. Theo tài liệu chính thức, thư viện hỗ trợ Memory Cache, Disk Cache và các phép biến đổi với tăng tốc phần cứng. Coil nổi bật với kích thước APK tối thiểu (khoảng 150 KB) và tương thích hoàn toàn với Jetpack Compose.

Những điểm chính

  • Coil là thư viện tải hình ảnh cho Android sử dụng Kotlin Coroutines và Kotlin Serialization.
  • ImageLoader là thành phần trung tâm quản lý các yêu cầu, bộ nhớ đệm và biến đổi hình ảnh.
  • Memory Cache lưu trữ hình ảnh bitmap đã giải mã trong RAM để truy cập tức thì.
  • Disk Cache lưu các tệp nén trên bộ nhớ để làm việc ngoại tuyến và giảm lưu lượng truy cập.
  • Jetpack Compose — thư viện hỗ trợ AsyncImage và SubcomposeAsyncImage cho UI khai báo.

Coil là gì?

Coil (Coroutine Image Loader) là thư viện tải hình ảnh cho Android, được viết hoàn toàn bằng Kotlin và sử dụng coroutines cho các hoạt động bất đồng bộ. Nó cung cấp API thống nhất để tải hình ảnh bitmap từ mạng, tài nguyên, hệ thống tệp và Content Provider, với bộ nhớ đệm tự động đa cấp.

Không giống như Glide và Picasso, Coil sử dụng Kotlin Coroutines thay vì chuỗi callback, làm cho mã trở nên tuyến tính và dự đoán được hơn. Tất cả các hoạt động tải và giải mã được thực thi trên các luồng nền thông qua bộ điều phối Dispatchers.IO, và kết quả được chuyển đến luồng chính mà không cần chuyển đổi rõ ràng.

Coil hỗ trợ các phép biến đổi (Round, Blur, Grayscale), hoạt ảnh chuyển tiếp, SVG và GIF, cũng như Target tùy chỉnh cho hiển thị không tiêu chuẩn. Theo Google I/O 2023, Coil được khuyến nghị trong các hướng dẫn chính thức về Jetpack Compose cùng với Glide.

  • Kích thước APK — khoảng 150 KB (so với 500 KB của Glide)
  • Phiên bản Android tối thiểu — API 21 (Lollipop)
  • Phụ thuộc — Kotlin Coroutines (tích hợp sẵn)

Cách Coil hoạt động: ImageLoader và ImageRequest

ImageLoader là thành phần chính của Coil, chịu trách nhiệm thực thi các yêu cầu tải và quản lý bộ nhớ đệm. Mỗi phiên bản chứa các tham chiếu đến MemoryCache, DiskCache, BitmapPool và một nhóm coroutines. Theo mặc định, một singleton được tạo qua Coil.imageLoader(context) được sử dụng.

ImageRequest

ImageRequest là một đối tượng mô tả một yêu cầu tải hình ảnh duy nhất: nguồn dữ liệu (URL, URI, tài nguyên Int), ImageView hoặc Target đích, các phép biến đổi, cài đặt bộ nhớ đệm và placeholder. ImageRequest được xây dựng thông qua builder, đảm bảo tính linh hoạt và dễ đọc.

kotlin
val request = ImageRequest.Builder(context)
    .data("https://example.com/image.jpg")
    .crossfade(true)
    .size(512, 512)
    .transformations(listOf(RoundedCornersTransformation(12f)))
    .memoryCachePolicy(CachePolicy.ENABLED)
    .diskCachePolicy(CachePolicy.ENABLED)
    .target(imageView)
    .build()

Sau khi xây dựng, ImageRequest được chuyển đến ImageLoader qua enqueue hoặc execute. Phương thức enqueue khởi chạy một coroutine và trả về Disposable, cho phép hủy tải khi rời khỏi màn hình. Phương thức execute là một hàm suspend trả về Result trực tiếp.

Luồng thực thi yêu cầu

ImageLoader tuần tự kiểm tra MemoryCache, DiskCache và chỉ khi cả hai đều không có mới thực thi yêu cầu mạng qua HttpEngine. Sau khi tải, các byte được giải mã thành Bitmap có tính đến kích thước mục tiêu, các phép biến đổi được áp dụng, kết quả được lưu trong cả hai bộ nhớ đệm và chuyển đến Target.

  • Memory Cache — được kiểm tra đầu tiên, khóa là URL + tham số
  • Disk Cache — được kiểm tra khi không có trong bộ nhớ, khóa là MD5 của URL
  • HttpEngine — OkHttp mặc định, có thể tùy chỉnh qua thành phần

Các thành phần chính của Coil

Coil được xây dựng trên kiến trúc thành phần với khả năng thay thế bất kỳ phần nào thông qua Tiêm phụ thuộc. Tất cả các thành phần được đăng ký trong ImageLoaderFactory và được chuyển đến hàm tạo ImageLoader qua builder.

ImageLoader

ImageLoader là điểm vào cho tất cả các hoạt động tải. Mỗi phiên bản chứa một nhóm coroutines, BitmapPool, MemoryCache, DiskCache và danh sách các bộ chặn. Theo mặc định, một phiên bản toàn cục được tạo, nhưng cho kiểm thử đơn vị, có thể tạo các phiên bản riêng biệt với bộ nhớ đệm cách ly.

MemoryCache

MemoryCache là bộ nhớ đệm trong RAM dựa trên LRU (Least Recently Used), lưu trữ các đối tượng Bitmap đã giải mã. Kích thước tối đa mặc định là 25% bộ nhớ khả dụng của ứng dụng, nhưng không dưới 32 MB. Khóa bộ nhớ đệm được hình thành từ URL + kích thước + biến đổi, ngăn chặn việc truy xuất hình ảnh lỗi thời.

DiskCache

DiskCache là bộ nhớ đệm dựa trên tệp cho dữ liệu thô (JPEG, PNG, WebP) và siêu dữ liệu đã giải mã. Nó nằm trong thư mục bộ nhớ đệm của ứng dụng và hỗ trợ dọn dẹp tự động khi vượt quá giới hạn. Các hoạt động đĩa được thực hiện qua DiskCache.Builder với cấu hình thư mục và kích thước tối đa.

Các cấp độ bộ nhớ đệm trong Coil

Coil triển khai chiến lược bộ nhớ đệm đa cấp giúp giảm thiểu yêu cầu mạng và tăng tốc hiển thị hình ảnh. Mỗi cấp độ có mục đích và thời gian sống của dữ liệu riêng.

Cấp độLoại lưu trữThời gian sốngKích thước mặc định
Memory CacheBitmap trong RAMCho đến khi bị LRU loại bỏ25% heap, từ 32 MB
Disk CacheTệp JPEG/WebPCho đến khi vượt quá giới hạn250 MB
Http CachePhản hồi OkHttpTheo tiêu đề Cache-ControlPhụ thuộc vào HTTP client

Memory Cache cung cấp truy cập tức thì đến các Bitmap đã giải mã. Disk Cache đảm bảo ứng dụng hoạt động không cần mạng (offline-first) sau lần tải đầu tiên. Http Cache ở cấp OkHttp xử lý các yêu cầu có điều kiện với ETag và If-Modified-Since.

Các chính sách bộ nhớ đệm được cấu hình theo từng yêu cầu qua CachePolicy với ba giá trị: ENABLED, READ_ONLY, WRITE_ONLY, DISABLED. Ví dụ, cho ảnh đại diện người dùng, có thể đặt READ_ONLY cho Memory Cache và ENABLED cho Disk Cache.

Ví dụ sử dụng Coil trong Kotlin

Coil cung cấp một số phương pháp tích hợp tùy theo kiến trúc ứng dụng. Hãy xem ba kịch bản chính với các ví dụ mã hoạt động.

Tải vào ImageView qua extension

load là một hàm mở rộng cho ImageView, cách đơn giản nhất để tải hình ảnh trong một dòng. Hàm này chấp nhận URL, URI, tài nguyên Int hoặc File, cùng với tất cả các tham số tùy chọn thông qua trình cấu hình lambda.

kotlin
imageView.load("https://example.com/photo.jpg") {
    crossfade(true)
    placeholder(R.drawable.placeholder)
    error(R.drawable.error)
    size(300, 300)
    transformations(CircleCropTransformation())
}

Phương thức load trả về một Disposable, có thể bị hủy trong onDestroy hoặc khi tái sử dụng View. Điều này ngăn rò rỉ bộ nhớ và các yêu cầu mạng không cần thiết trong quá trình cuộn danh sách nhanh.

Sử dụng trong Jetpack Compose

AsyncImage là một hàm composable để tải hình ảnh trong UI khai báo. Nó chấp nhận bất kỳ nguồn dữ liệu nào và ba tham số tùy chọn cho các trạng thái: placeholder, error và success.

kotlin
@Composable
fun NetworkImage(url: String) {
    AsyncImage(
        model = url,
        contentDescription = "hình ảnh mạng",
        placeholder = ColorPainter(Color.Gray),
        error = ColorPainter(Color.Red)
    )
}

SubcomposeAsyncImage là phiên bản linh hoạt hơn cho phép tùy chỉnh hiển thị trong quá trình tải thông qua khe nội dung. Điều này hữu ích cho khung xương (shimmer) và thanh tiến trình.

Target tùy chỉnh cho đầu ra không tiêu chuẩn

Nếu ImageView hoặc AsyncImage không phù hợp, bạn có thể triển khai Target với một phương thức onSuccess duy nhất chấp nhận Bitmap. Điều này được sử dụng để tải vào Notification, RemoteViews hoặc kết cấu OpenGL.

kotlin
val target = object : BitmapTarget() {
    override fun onSuccess(result: Bitmap) {
        notificationRemoteView.setImageViewBitmap(R.id.icon, result)
    }
}

imageLoader.enqueue(
    ImageRequest.Builder(context)
        .data(url)
        .target(target)
        .build()
)

So sánh Coil với các thư viện khác

Việc chọn thư viện tải hình ảnh phụ thuộc vào yêu cầu của dự án. Coil cạnh tranh với Glide và Picasso, mỗi thư viện có điểm mạnh riêng. So sánh các đặc điểm chính được trình bày trong bảng.

Đặc điểmCoilGlidePicasso
Ngôn ngữKotlin (100%)Java + KotlinJava
Kích thước APK~150 KB~500 KB~120 KB
CoroutinesTích hợp sẵnKhông (callback)Không (callback)
Jetpack ComposeHỗ trợ gốcQua accompanistBên thứ ba
GIF/WebPCó (tích hợp sẵn)Có (tích hợp sẵn)Không
Khuyến nghị GoogleCó (I/O 2023)Không

Đối với các dự án mới trên Kotlin và Jetpack Compose, Coil trở thành lựa chọn tự nhiên nhờ không có phụ thuộc coroutines bổ sung và kích thước tối thiểu. Glide vẫn được ưa chuộng cho các kịch bản phức tạp với hoạt ảnh và xem trước video. Picasso thua kém cả hai về chức năng nhưng thắng về sự đơn giản.

Thiết lập Coil trong dự án Android

Việc thêm Coil vào dự án Android được thực hiện thông qua phụ thuộc Gradle. Sau khi thêm, thư viện tự động đăng ký ImageLoader qua ContentProvider, do đó không cần khởi tạo thủ công trong Application. Nếu cần tùy chỉnh, một ImageLoader tùy chỉnh được tạo qua builder.

kotlin
// build.gradle.kts (app module)
dependencies {
    implementation("io.coil-kt:coil:2.6.0")
    // Cho Jetpack Compose thêm:
    implementation("io.coil-kt:coil-compose:2.6.0")
    // Cho hỗ trợ SVG:
    implementation("io.coil-kt:coil-svg:2.6.0")
    // Cho hỗ trợ GIF:
    implementation("io.coil-kt:coil-gif:2.6.0")
}

Để tùy chỉnh ImageLoader, ImageLoaderFactory được sử dụng — một singleton được tạo trong Application.onCreate. Trong factory, bạn có thể cấu hình giới hạn bộ nhớ đệm, HTTP client, bộ giải mã tùy chỉnh và ghi nhật ký. Theo mặc định, Coil sử dụng OkHttp với một nhóm kết nối sẵn sàng.

kotlin
class App : Application(), ImageLoaderFactory {
    override fun newImageLoader(): ImageLoader {
        return ImageLoader.Builder(this)
            .memoryCache {
                MemoryCache.Builder()
                    .maxSizePercent(0.25)
                    .build()
            }
            .diskCache {
                DiskCache.Builder()
                    .directory(cacheDir.resolve("coil_cache"))
                    .maxSizeBytes(512 * 1024 * 1024)
                    .build()
            }
            .build()
    }
}

Câu hỏi thường gặp

Coil là gì và nó được sử dụng để làm gì?

Coil là thư viện tải hình ảnh cho Android, được viết bằng Kotlin sử dụng coroutines. Nó được sử dụng để tải bất đồng bộ, lưu vào bộ nhớ đệm và hiển thị hình ảnh bitmap từ mạng, tài nguyên hoặc hệ thống tệp.

Coil khác Glide như thế nào?

Coil được viết 100% bằng Kotlin và sử dụng coroutines thay vì cơ chế callback của Glide. Coil có kích thước APK nhỏ hơn (~150 KB so với ~500 KB) và hỗ trợ gốc Jetpack Compose qua AsyncImage.

Làm thế nào để thêm Coil vào dự án Kotlin?

Thêm phụ thuộc io.coil-kt:coil:2.6.0 vào build.gradle.kts. Cho Jetpack Compose, cũng thêm io.coil-kt:coil-compose:2.6.0. Thư viện tự động đăng ký ImageLoader qua ContentProvider.

Coil hỗ trợ những loại hình ảnh nào?

Coil hỗ trợ JPEG, PNG, WebP, BMP, SVG (qua mô-đun coil-svg) và GIF (qua mô-đun coil-gif). Các định dạng AVIF và HEIF được hỗ trợ qua bộ giải mã tùy chỉnh trên thiết bị Android 10+.

Làm thế nào để cấu hình bộ nhớ đệm trong Coil?

Bộ nhớ đệm được cấu hình qua ImageLoader.Builder: memoryCache với tỷ lệ phần trăm của heap, diskCache với đường dẫn và giới hạn tính bằng byte. Các chính sách bộ nhớ đệm (ENABLED, DISABLED, READ_ONLY) được cấu hình theo từng yêu cầu qua CachePolicy.

Tóm tắt

  • Coil là thư viện tải hình ảnh cho Kotlin với hỗ trợ đầy đủ coroutines và Jetpack Compose.
  • ImageLoader quản lý các yêu cầu, bộ nhớ đệm và biến đổi, sử dụng hai cấp bộ nhớ đệm: Memory Cache và Disk Cache.
  • AsyncImageSubcomposeAsyncImage cung cấp tích hợp Compose, hỗ trợ các trạng thái placeholder, error và success.
  • Kích thước APK ~150 KB làm cho Coil trở thành một trong những thư viện tải hình ảnh nhỏ gọn nhất trên thị trường.
  • Các phép biến đổi (RoundedCorners, CircleCrop, Blur) được tích hợp trong thư viện và hoạt động với tăng tốc phần cứng.
  • Disk Cache cung cấp truy cập ngoại tuyến đến hình ảnh đã tải trước đó với giới hạn lưu trữ có thể cấu hình.
  • Coil được Google khuyến nghị trong các hướng dẫn chính thức về Jetpack Compose, xác nhận vị thế tiêu chuẩn hiện đại của nó.

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm