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 (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.
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 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.
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.
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.
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 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 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 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.
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ống | Kích thước mặc định |
|---|---|---|---|
| Memory Cache | Bitmap trong RAM | Cho đến khi bị LRU loại bỏ | 25% heap, từ 32 MB |
| Disk Cache | Tệp JPEG/WebP | Cho đến khi vượt quá giới hạn | 250 MB |
| Http Cache | Phản hồi OkHttp | Theo tiêu đề Cache-Control | Phụ 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.
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.
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.
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.
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.
@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.
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.
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()
)
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ểm | Coil | Glide | Picasso |
|---|---|---|---|
| Ngôn ngữ | Kotlin (100%) | Java + Kotlin | Java |
| Kích thước APK | ~150 KB | ~500 KB | ~120 KB |
| Coroutines | Tích hợp sẵn | Không (callback) | Không (callback) |
| Jetpack Compose | Hỗ trợ gốc | Qua accompanist | Bên thứ ba |
| GIF/WebP | Có (tích hợp sẵn) | Có (tích hợp sẵn) | Không |
| Khuyến nghị Google | Có (I/O 2023) | Có | 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.
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.
// 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.
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à 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 đượ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.
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ợ 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+.
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
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.
Đọc thêm