Upgrading to Coil 2.x¶
This is a short guide to highlight the main changes when upgrading from Coil 1.x to 2.x and how to handle them. This upgrade guide doesn't cover every binary or source incompatible change, but it does cover the most important changes.
Minimum API 21¶
Coil 2.x requires minimum API 21. This is also the minimum API required for Compose and OkHttp 4.x.
ImageRequest default scale¶
Coil 2.x changes ImageRequest's default scale from Scale.FILL to Scale.FIT. This was done to be consistent with ImageView's default ScaleType and Image's default ContentScale. Scale is still autodetected if you set an ImageView as your ImageRequest.target.
Size refactor¶
Size's width and height are now two Dimensions instead of Int pixel values. Dimension is either a pixel value or Dimension.Undefined, which represents an undefined/unbounded constraint. For example, if the size is Size(400, Dimension.Undefined) that means the image should be scaled to have 400 pixels for its width irrespective of its height. You can use the pxOrElse extension to get the pixel value (if present), else use a fallback:
This change was made to improve support for cases where a target has one unbounded dimension (e.g. if one dimension is ViewGroup.LayoutParams.WRAP_CONTENT for a View or Constraints.Infinity in Compose).
Compose¶
Coil 2.x significantly reworks the Compose integration to add features, improve stability, and improve performance.
In Coil 1.x you would use rememberImagePainter to load an image:
val painter = rememberImagePainter("https://example.com/image.jpg") {
crossfade(true)
}
Image(
painter = painter,
contentDescription = null,
contentScale = ContentScale.Crop
)
In Coil 2.x rememberImagePainter has been changed to rememberAsyncImagePainter with the following changes:
- The trailing lambda argument to configure the
ImageRequesthas been removed. - In Coil 2.x,
rememberAsyncImagePainterdefaults to usingContentScale.Fitto be consistent withImagewhereas in Coil 1.x it would default toContentScale.Crop. As such, if you set a customContentScaleonImage, you now also need to pass it torememberAsyncImagePainter.
val painter = rememberAsyncImagePainter(
model = ImageRequest.Builder(LocalContext.current)
.data("https://example.com/image.jpg")
.crossfade(true)
.build(),
contentScale = ContentScale.Crop
)
Image(
painter = painter,
contentDescription = null,
contentScale = ContentScale.Crop
)
Additionally, Coil now has AsyncImage and SubcomposeAsyncImage composable functions, which add new features and work-around some design limitations of rememberAsyncImagePainter. Check out the full Compose docs here.
Disk Cache¶
Coil 2.x has its own public disk cache class that can be accessed using imageLoader.diskCache. Coil 1.x relied on OkHttp's disk cache, however it's no longer needed.
To configure the disk cache in 1.x you would use CoilUtils.createDefaultCache:
ImageLoader.Builder(context)
.okHttpClient {
OkHttpClient.Builder().cache(CoilUtils.createDefaultCache(context)).build()
}
.build()
In Coil 2.x you should not set a Cache object on your OkHttpClient when used with an ImageLoader. Instead configure the disk cache object like so:
ImageLoader.Builder(context)
.diskCache {
DiskCache.Builder()
.directory(context.cacheDir.resolve("image_cache"))
.build()
}
.build()
This change was made to add functionality and improve performance:
- Support thread interruption while decoding images.
- Thread interruption allows fast cancellation of decode operations. This is particularly important for quickly scrolling through a list.
- By using a custom disk cache Coil is able to ensure a network source is fully read to disk before decoding. This is necessary as writing the data to disk cannot be interrupted - only the decode step can be interrupted. OkHttp's
Cacheshouldn't be used with Coil 2.0 as it's not possible to guarantee that all data is written to disk before decoding. - Avoid buffering/creating temporary files for decode APIs that don't support
InputStreams or require direct access to aFile(e.g.ImageDecoder,MediaMetadataRetriever). - Add a public read/write
DiskCacheAPI.
In Coil 2.x Cache-Control and other cache headers are still supported - except Vary headers, as the cache only checks that the URLs match. Additionally, only responses with a response code in the range [200..300) are cached.
When upgrading from Coil 1.x to 2.x, any existing disk cache will be cleared as the internal format has changed.
Image pipeline refactor¶
Coil 2.x refactors the image pipeline classes to be more flexible. Here's a high-level list of the changes:
- Introduce a new class,
Keyer, that computes the memory cache key for a request. It replacesFetcher.key. Mapper,Keyer,Fetcher, andDecodercan returnnullto delegate to the next element in the list of components.- Add
OptionstoMapper.map's signature. - Introduce
Fetcher.FactoryandDecoder.Factory. Use the factories to determine if a specificFetcher/Decoderis applicable. Returnnullif thatFetcher/Decoderis not applicable.
Remove bitmap pooling¶
Coil 2.x removes bitmap pooling and its associated classes (BitmapPool, PoolableViewTarget). See here for why it was removed.