Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Uncoiling the COIL - Understanding modern image loading on Android

Uncoiling the COIL - Understanding modern image loading on Android

Image loading is hard but luckily this problem has already been addressed on Android. There are many libraries out there that handle image loading seamlessly. COIL is the new kid to the club and you may be wondering why do we need another image loading library?

COIL is Kotlin first library backed by Kotlin Coroutines. It gives you an easy and concise API to deal with image loading. Oh and also it takes less space! In a nutshell, it's an easy to use, fast, lightweight, and modern library.

This talk will address
- Why you should consider this library for image loading?
- Understanding its API.
- How it works? by covering its entire image loading pipeline.

By the end, you'll walk away with the advantages of using COIL and its image loading pipeline.

Sagar Viradiya

June 26, 2021
Tweet

More Decks by Sagar Viradiya

Other Decks in Programming

Transcript

  1. Agenda • What is COIL? • Why COIL? • How

    COIL? • Image loading pipeline • In memory caching
  2. What is COIL? • COroutine Image Loader • An image

    loading library for android (Another? 🤔)
  3. API val imageLoader = context.imageLoader OR val imageLoader = ImageLoader.Builder(context)

    .availableMemoryPercentage(0.25) .crossfade(true) .build()
  4. Imperative style // Coroutine scope val request = ImageRequest.Builder(context) .data("https:////w.example.com/image.jpg")

    .build() val result = imageLoader.execute(request) // Suspends the execution val drawable = result.drawable
  5. Jetpack Compose Support Image( painter = rememberImagePainter( data = "https:////w.example.com/image.jpg",

    builder = { transformations(CircleCropTransformation()) crossfade(true) } ), contentDescription = null, modifier = Modifier.size(128.dp) )
  6. ImageLoader • A service class responsible for executing and managing

    entire pipeline. • Takes ImageRequest. • COIL provides singleton (Recommended)
  7. Interceptors • Allows you to observe, transform, short circuit or

    retry request • You can wrap the pipeline with your custom logic
  8. Interceptors • Allows you to observe, transform, short circuit or

    retry request • You can wrap the pipeline with your custom logic • Inspired from OKHttp’s interceptor
  9. class CustomCacheInterceptor( private val context: Context, private val cache: LruCache<String,

    Drawable> ) : Interceptor { override suspend fun intercept(chain: Interceptor.Chain): ImageResult { val value = cache.get(chain.request.data.toString()) if (value /= null) { return SuccessResult( drawable = value.bitmap.toDrawable(context), request = chain.request, metadata = TODO() ) } return chain.proceed(chain.request) } }
  10. class CustomCacheInterceptor( private val context: Context, private val cache: LruCache<String,

    Drawable> ) : Interceptor { override suspend fun intercept(chain: Interceptor.Chain): ImageResult { val value = cache.get(chain.request.data.toString()) if (value /= null) { return SuccessResult( drawable = value.bitmap.toDrawable(context), request = chain.request, metadata = TODO() ) } return chain.proceed(chain.request) } }
  11. class CustomCacheInterceptor( private val context: Context, private val cache: LruCache<String,

    Drawable> ) : Interceptor { override suspend fun intercept(chain: Interceptor.Chain): ImageResult { val value = cache.get(chain.request.data.toString()) if (value /= null) { return SuccessResult( drawable = value.bitmap.toDrawable(context), request = chain.request, metadata = TODO() ) } return chain.proceed(chain.request) } }
  12. class CustomCacheInterceptor( private val context: Context, private val cache: LruCache<String,

    Drawable> ) : Interceptor { override suspend fun intercept(chain: Interceptor.Chain): ImageResult { val value = cache.get(chain.request.data.toString()) if (value /= null) { return SuccessResult( drawable = value.bitmap.toDrawable(context), request = chain.request, metadata = TODO() ) } return chain.proceed(chain.request) } }
  13. class CustomCacheInterceptor( private val context: Context, private val cache: LruCache<String,

    Drawable> ) : Interceptor { override suspend fun intercept(chain: Interceptor.Chain): ImageResult { val value = cache.get(chain.request.data.toString()) if (value /= null) { return SuccessResult( drawable = value.bitmap.toDrawable(context), request = chain.request, metadata = TODO() ) } return chain.proceed(chain.request) } }
  14. Mapper - Example data class Item( val id: Int, val

    imageUrl: String, val price: Int, val weight: Double ) class ItemMapper : Mapper<Item, String> { override fun map(data: Item) = data.imageUrl }
  15. Mapper - Example data class Item( val id: Int, val

    imageUrl: String, val price: Int, val weight: Double ) class ItemMapper : Mapper<Item, String> { override fun map(data: Item) = data.imageUrl }
  16. Fetcher • Translates data into either BufferedSource or Drawable •

    Built-in fetchers ◦ AssetUriFetcher ◦ ContentUriFetcher ◦ FileFetcher ◦ HttpFetcher
  17. Custom Fetcher interface Fetcher<T : Any> { fun handles(data: T):

    Boolean = true fun key(data: T): String? suspend fun fetch( pool: BitmapPool, data: T, size: Size, options: Options ): FetchResult }
  18. Decoder • Converts BufferedSource to Drawable • Built-in format support

    ◦ JPEG ◦ PNG ◦ WebPs • Extensions ◦ SVG ◦ GIFs/HEIFs ◦ Video frame
  19. Custom Decoder interface Decoder { fun handles(source: BufferedSource, mimeType: String?):

    Boolean suspend fun decode( pool: BitmapPool, source: BufferedSource, size: Size, options: Options ): DecodeResult }
  20. Transformation • Allows you to change the pixel data. •

    Built-in transformations ◦ Blur ◦ Circle crop ◦ Grayscale ◦ Rounded corner
  21. Custom Transformation interface Transformation { fun key(): String suspend fun

    transform(pool: BitmapPool, input: Bitmap, size: Size): Bitmap }
  22. Engine Interceptor Is in strong memory? Key Yes Return Bitmap

    and short circuit image loading pipeline
  23. Engine Interceptor Is in strong memory? Key Yes Return Bitmap

    and short circuit image loading pipeline No Is in weak memory?
  24. Engine Interceptor Is in strong memory? Key Yes Return Bitmap

    and short circuit image loading pipeline No Is in weak memory? Yes Return Bitmap and short circuit image loading pipeline
  25. Engine Interceptor Is in strong memory? Key Yes Return Bitmap

    and short circuit image loading pipeline No Is in weak memory? No Execute Image loading pipeline Yes Return Bitmap and short circuit image loading pipeline
  26. Strong Memory Cache • Backed by LRU cache • Size

    of the cache is computed dynamically
  27. Strong Memory Cache Req. Image 3 Strong Memory Cache Weak

    Memory Cache Image 1 Image 2 Image 3
  28. Strong Memory Cache Req. Image 4 Strong Memory Cache Weak

    Memory Cache Image 1 Image 2 Image 3 Image 4
  29. Summary • COIL - Coroutine Image Loader • Modern, Easy,

    Lightweight and Fast • API • Image loading pipeline • In memory caching