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

Uncoiling the COIL Vol 2 - Droidcon Italy

Uncoiling the COIL Vol 2 - Droidcon Italy

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

November 11, 2021
Tweet

More Decks by Sagar Viradiya

Other Decks in Programming

Transcript

  1. Uncoiling the COIL - Vol 2
    @viradiya_sagar
    Understanding modern image loading on Android
    Android at

    View Slide

  2. We are hiring!
    https://careers.deliveryhero.com/global/en

    View Slide

  3. COIL 2.0
    Alpha02

    View Slide

  4. Agenda
    ● What is COIL?
    ● Why COIL?
    ● How COIL?
    ● Image loading pipeline
    ● Caching

    View Slide

  5. What is COIL?

    View Slide

  6. What is COIL?
    ● COroutine Image Loader

    View Slide

  7. What is COIL?
    ● COroutine Image Loader
    ● An image loading library for android (Another? 🤔)

    View Slide

  8. Why COIL?
    ● Modern

    View Slide

  9. Why COIL?
    ● Modern
    ● Easy to use

    View Slide

  10. Why COIL?
    ● Modern
    ● Easy to use
    ● Lightweight

    View Slide

  11. Why COIL?
    ● Modern
    ● Easy to use
    ● Lightweight
    ● Fast

    View Slide

  12. API
    val imageRequest = ImageRequest.Builder(context)
    .data("https://www.example.com/image.jpg")
    .crossfade(true)
    .target(imageView)
    .build()

    View Slide

  13. API
    val imageLoader = context.imageLoader
    OR
    val imageLoader = ImageLoader.Builder(context)
    .availableMemoryPercentage(0.25)
    .crossfade(true)
    .build()

    View Slide

  14. API
    val disposable = imageLoader.enqueue(imageRequest)

    View Slide

  15. Kotlin syntactic sugar
    // URL
    imageView.load("https://www.example.com/image.jpg")
    // Resource
    imageView.load(R.drawable.image)
    // File
    imageView.load(File("/path/to/image.jpg"))
    // And more...

    View Slide

  16. Kotlin syntactic sugar
    imageView.load("https://www.example.com/image.jpg")

    View Slide

  17. Kotlin syntactic sugar
    imageView.load("https://www.example.com/image.jpg") {
    crossfade(true)
    placeholder(R.drawable.image)
    transformations(CircleCropTransformation())
    }

    View Slide

  18. Imperative style
    // Coroutine scope
    val request = ImageRequest.Builder(context)
    .data("https://www.example.com/image.jpg")
    .build()
    val result = imageLoader.execute(request) // Suspends the execution
    val drawable = result.drawable

    View Slide

  19. Jetpack Compose Support
    Image(
    painter = rememberImagePainter("https://www.example.com/image.jpg"),
    contentDescription = null,
    modifier = Modifier.size(128.dp)
    )

    View Slide

  20. Jetpack Compose Support
    Image(
    painter = rememberImagePainter(
    data = "https://www.example.com/image.jpg",
    builder = {
    transformations(CircleCropTransformation())
    crossfade(true)
    }
    ),
    contentDescription = null,
    modifier = Modifier.size(128.dp)
    )

    View Slide

  21. The pipeline
    ImageLoader Interceptor
    ImageRequest
    Mapper Fetcher
    Decoder
    Transformation
    ImageResult
    SuccessResult ErrorResult

    View Slide

  22. The pipeline
    ImageLoader Interceptor
    ImageRequest
    Mapper Fetcher
    Decoder
    Transformation
    ImageResult
    SuccessResult ErrorResult

    View Slide

  23. The pipeline
    ImageLoader Interceptor
    ImageRequest
    Mapper Fetcher
    Decoder
    Transformation
    ImageResult
    SuccessResult ErrorResult
    data: T

    View Slide

  24. The pipeline
    ImageLoader Interceptor
    ImageRequest
    Mapper Fetcher
    Decoder
    Transformation
    ImageResult
    SuccessResult ErrorResult
    data: T data: T

    View Slide

  25. The pipeline
    ImageLoader Interceptor
    ImageRequest
    Mapper Fetcher
    Decoder
    Transformation
    ImageResult
    SuccessResult ErrorResult
    data: T data: T data: M

    View Slide

  26. The pipeline
    ImageLoader Interceptor
    ImageRequest
    Mapper Fetcher
    Decoder
    Transformation
    ImageResult
    SuccessResult ErrorResult
    data: T data: T data: M
    FetchResult

    View Slide

  27. The pipeline
    ImageLoader Interceptor
    ImageRequest
    Mapper Fetcher
    Decoder
    Transformation
    ImageResult
    SuccessResult ErrorResult
    data: T data: T data: M
    FetchResult
    DecodeResult

    View Slide

  28. The pipeline
    ImageLoader Interceptor
    ImageRequest
    Mapper Fetcher
    Decoder
    Transformation
    ImageResult
    SuccessResult
    data: T data: T data: M
    FetchResult
    DecodeResult
    ErrorResult

    View Slide

  29. The pipeline
    ImageLoader Interceptor
    ImageRequest
    Mapper Fetcher
    Decoder
    Transformation
    ImageResult
    SuccessResult
    data: T data: T data: M
    FetchResult
    DecodeResult
    ErrorResult

    View Slide

  30. The pipeline
    ImageLoader Interceptor
    ImageRequest
    Mapper Fetcher
    Decoder
    Transformation
    ImageResult
    SuccessResult
    data: T data: T data: M
    FetchResult
    DecodeResult
    ErrorResult

    View Slide

  31. The pipeline
    ImageLoader Interceptor
    ImageRequest
    Mapper Fetcher
    Decoder
    Transformation
    ImageResult
    SuccessResult ErrorResult

    View Slide

  32. ImageLoader
    ● A service class responsible for executing and managing
    entire pipeline.

    View Slide

  33. ImageLoader
    ● A service class responsible for executing and managing
    entire pipeline.
    ● Takes ImageRequest.

    View Slide

  34. ImageLoader
    ● A service class responsible for executing and managing
    entire pipeline.
    ● Takes ImageRequest.
    ● COIL provides singleton (Recommended)

    View Slide

  35. The pipeline
    ImageLoader Interceptor
    ImageRequest
    Mapper Fetcher
    Decoder
    Transformation
    ImageResult
    SuccessResult ErrorResult
    data: T

    View Slide

  36. Interceptor

    View Slide

  37. Interceptor
    ● Allows you to observe, transform, short circuit or retry
    request

    View Slide

  38. Interceptor
    ● Allows you to observe, transform, short circuit or retry
    request
    ● You can wrap the pipeline with your custom logic

    View Slide

  39. Interceptor
    ● Allows you to observe, transform, short circuit or retry
    request
    ● You can wrap the pipeline with your custom logic
    ● Inspired from OKHttp’s interceptor

    View Slide

  40. class CustomCacheInterceptor(
    private val context: Context,
    private val cache: LruCache
    ) : 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)
    }
    }

    View Slide

  41. class CustomCacheInterceptor(
    private val context: Context,
    private val cache: LruCache
    ) : 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)
    }
    }

    View Slide

  42. class CustomCacheInterceptor(
    private val context: Context,
    private val cache: LruCache
    ) : 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)
    }
    }

    View Slide

  43. class CustomCacheInterceptor(
    private val context: Context,
    private val cache: LruCache
    ) : 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)
    }
    }

    View Slide

  44. class CustomCacheInterceptor(
    private val context: Context,
    private val cache: LruCache
    ) : 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)
    }
    }

    View Slide

  45. Plugin custom interceptor
    val imageLoader = ImageLoader.Builder(context)
    .components {
    add(CustomCacheInterceptor())
    }
    .build()

    View Slide

  46. EngineInterceptor
    ● The last interceptor in the chain

    View Slide

  47. EngineInterceptor
    ● The last interceptor in the chain
    ● Responsible for checking in memory cache

    View Slide

  48. The pipeline
    ImageLoader Interceptor
    ImageRequest
    Mapper Fetcher
    Decoder
    Transformation
    ImageResult
    SuccessResult ErrorResult
    data: T data: T

    View Slide

  49. Mapper
    ● Allows you to add support for custom data types

    View Slide

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

    View Slide

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

    View Slide

  52. Mapper - Example
    imageView.load(item)

    View Slide

  53. Plugin custom mapper
    val imageLoader = ImageLoader.Builder(context)
    .components {
    add(ItemMapper())
    }
    .build()

    View Slide

  54. The pipeline
    ImageLoader Interceptor
    ImageRequest
    Mapper Fetcher
    Decoder
    Transformation
    ImageResult
    SuccessResult ErrorResult
    data: T data: T data: M

    View Slide

  55. Fetcher
    ● Translates data into either ImageSource or Drawable

    View Slide

  56. Fetcher
    ● Translates data into either ImageSource or Drawable
    ● Built-in fetchers
    ○ AssetUriFetcher
    ○ ContentUriFetcher
    ○ FileFetcher
    ○ HttpFetcher

    View Slide

  57. Custom Fetcher
    interface Fetcher {
    suspend fun fetch(): FetchResult?
    fun interface Factory {
    fun create(data: T, options: Options, imageLoader: ImageLoader): Fetcher?
    }
    }

    View Slide

  58. Plugin custom fetcher
    val imageLoader = ImageLoader.Builder(context)
    .components {
    add(MyFetcher.Factory())
    }
    .build()

    View Slide

  59. The pipeline
    ImageLoader Interceptor
    ImageRequest
    Mapper Fetcher
    Decoder
    Transformation
    ImageResult
    SuccessResult ErrorResult
    data: T data: T data: M
    FetchResult

    View Slide

  60. Decoder
    ● Converts ImageSource to Drawable

    View Slide

  61. Decoder
    ● Converts ImageSource to Drawable
    ● Built-in format support
    ○ JPEG
    ○ PNG
    ○ WebPs

    View Slide

  62. Decoder
    ● Converts ImageSource to Drawable
    ● Built-in format support
    ○ JPEG
    ○ PNG
    ○ WebPs
    ● Extensions
    ○ SVG
    ○ GIFs/HEIFs
    ○ Video frame

    View Slide

  63. Custom Decoder
    interface Decoder {
    suspend fun decode(): DecodeResult?
    fun interface Factory {
    fun create(
    result: SourceResult,
    options: Options,
    imageLoader: ImageLoader
    ): Decoder?
    }
    }

    View Slide

  64. Plugin custom decoder
    val imageLoader = ImageLoader.Builder(context)
    .components {
    add(MyDecoder.Factory())
    }
    .build()

    View Slide

  65. The pipeline
    ImageLoader Interceptor
    ImageRequest
    Mapper Fetcher
    Decoder
    Transformation
    ImageResult
    SuccessResult ErrorResult
    data: T data: T data: M
    FetchResult
    DecodeResult

    View Slide

  66. Transformation
    ● Allows you to change the pixel data.

    View Slide

  67. Transformation
    ● Allows you to change the pixel data.
    ● Built-in transformations
    ○ Circle crop
    ○ Rounded corner

    View Slide

  68. Custom Transformation
    interface Transformation {
    val cacheKey: String
    suspend fun transform(input: Bitmap, size: Size): Bitmap
    }

    View Slide

  69. The pipeline
    ImageLoader Interceptor
    ImageRequest
    Mapper Fetcher
    Decoder
    Transformation
    ImageResult
    SuccessResult ErrorResult
    data: T data: T data: M
    FetchResult
    DecodeResult

    View Slide

  70. The pipeline
    ImageLoader Interceptor
    ImageRequest
    Mapper Fetcher
    Decoder
    Transformation
    ImageResult
    SuccessResult ErrorResult
    data: T data: T data: M
    FetchResult
    DecodeResult

    View Slide

  71. The pipeline
    ImageLoader Interceptor
    ImageRequest
    Mapper Fetcher
    Decoder
    Transformation
    ImageResult
    SuccessResult ErrorResult
    data: T data: T data: M
    FetchResult
    DecodeResult

    View Slide

  72. Thread
    Interceptor
    Mapper
    Fetcher
    Decoder
    Transformation
    Transition
    Main Thread
    Default - I/O Thread
    OR
    Based on custom
    dispatchers
    Main Thread

    View Slide

  73. Caching

    View Slide

  74. Caching
    ● Disk cache

    View Slide

  75. Caching
    ● Disk cache
    ● In memory cache

    View Slide

  76. Disk cache

    View Slide

  77. Disk cache
    ● Coil 2.0 has its own disk cache

    View Slide

  78. Disk cache
    ● Coil 2.0 has its own disk cache
    ● Prior versions relies on OkHttp disk cache

    View Slide

  79. HttpUriFetcher

    View Slide

  80. HttpUriFetcher
    URL
    Disk Cache

    View Slide

  81. HttpUriFetcher
    URL
    Disk Cache
    Snapshot?

    View Slide

  82. HttpUriFetcher
    URL
    Disk Cache
    Snapshot?
    Snapshot !=
    null

    View Slide

  83. HttpUriFetcher
    URL
    Disk Cache
    Snapshot?
    Snapshot !=
    null
    Pass result to
    decoder
    Yes

    View Slide

  84. HttpUriFetcher
    URL
    Disk Cache
    Snapshot?
    Snapshot !=
    null
    Pass result to
    decoder
    No
    Yes
    Fetch image
    from source

    View Slide

  85. HttpUriFetcher
    URL
    Disk Cache
    Snapshot?
    Snapshot !=
    null
    Pass result to
    decoder
    No
    Yes
    Fetch image
    from source
    N/W

    View Slide

  86. HttpUriFetcher
    URL
    Disk Cache
    Snapshot?
    Snapshot !=
    null
    Pass result to
    decoder
    No
    Yes
    Fetch image
    from source
    N/W
    Image
    data

    View Slide

  87. HttpUriFetcher
    URL
    Disk Cache
    Snapshot?
    Snapshot !=
    null
    Pass result to
    decoder
    No
    Yes
    Fetch image
    from source
    N/W
    Write
    Image
    data

    View Slide

  88. HttpUriFetcher
    URL
    Disk Cache
    Snapshot?
    Snapshot !=
    null
    Pass result to
    decoder
    No
    Yes
    Fetch image
    from source
    N/W
    Write
    Image
    data
    Read

    View Slide

  89. HttpUriFetcher
    URL
    Disk Cache
    Snapshot?
    Snapshot !=
    null
    Pass result to
    decoder
    No
    Yes
    Fetch image
    from source
    N/W
    Write
    Image
    data
    Pass result to
    decoder
    Read

    View Slide

  90. HttpUriFetcher
    URL
    Disk Cache
    Snapshot?
    Snapshot !=
    null
    Pass result to
    decoder
    No
    Yes
    Fetch image
    from source
    N/W
    Write
    Image
    data
    Pass result to
    decoder
    Read

    View Slide

  91. Disk Cache
    interface DiskCache {
    operator fun get(key: String): Snapshot?
    fun edit(key: String): Editor?
    fun remove(key: String): Boolean
    fun clear()
    interface Snapshot : Closeable
    interface Editor
    }

    View Slide

  92. Disk Cache
    interface DiskCache {
    operator fun get(key: String): Snapshot?
    fun edit(key: String): Editor?
    fun remove(key: String): Boolean
    fun clear()
    interface Snapshot : Closeable
    interface Editor
    }

    View Slide

  93. Disk Cache
    interface DiskCache {
    operator fun get(key: String): Snapshot?
    fun edit(key: String): Editor?
    fun remove(key: String): Boolean
    fun clear()
    interface Snapshot : Closeable
    interface Editor
    }

    View Slide

  94. Disk Cache
    interface DiskCache {
    operator fun get(key: String): Snapshot?
    fun edit(key: String): Editor?
    fun remove(key: String): Boolean
    fun clear()
    interface Snapshot : Closeable
    interface Editor
    }

    View Slide

  95. Disk Cache
    interface DiskCache {
    operator fun get(key: String): Snapshot?
    fun edit(key: String): Editor?
    fun remove(key: String): Boolean
    fun clear()
    interface Snapshot : Closeable
    interface Editor
    }

    View Slide

  96. LRU Disk Cache
    ● Snapshot

    View Slide

  97. Snapshot
    ● Result of the cache read operation

    View Slide

  98. Snapshot
    ● Result of the cache read operation
    ● Encapsulates cache entry

    View Slide

  99. Snapshot
    ● Result of the cache read operation
    ● Encapsulates cache entry
    ● Gives access to the cache file object

    View Slide

  100. LRU Disk Cache
    ● Snapshot
    ● Editor

    View Slide

  101. Editor
    ● Allows disk writing

    View Slide

  102. Editor
    ● Allows disk writing
    ● Gives access to the cache file (Dirty file)

    View Slide

  103. LRU Disk Cache
    ● Snapshot
    ● Editor
    ● LinkedHashMap

    View Slide

  104. LinkedHashMap
    ● In memory representation of a disk cache

    View Slide

  105. LinkedHashMap
    ● In memory representation of a disk cache
    ● Entry is an object holding cache entry files
    ○ Clean file
    ○ Dirty file

    View Slide

  106. LinkedHashMap
    ● In memory representation of a disk cache
    ● Entry is an object holding cache entry files
    ○ Clean file
    ○ Dirty file
    ● Keeps track of cache entry status

    View Slide

  107. File System
    Journal File
    Image files

    View Slide

  108. libcore.io.DiskLruCache
    1
    100
    2
    CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054
    DIRTY 335c4c6028171cfddfbaae1a9c313c52
    CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342
    REMOVE 335c4c6028171cfddfbaae1a9c313c52
    DIRTY 1ab96a171faeeee38496d8b330771a7a
    CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234
    READ 335c4c6028171cfddfbaae1a9c313c52
    READ 3400330d1dfc7f3f7f4b8d4d803dfcf6
    Journal file

    View Slide

  109. libcore.io.DiskLruCache
    1
    100
    2
    CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054
    DIRTY 335c4c6028171cfddfbaae1a9c313c52
    CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342
    REMOVE 335c4c6028171cfddfbaae1a9c313c52
    DIRTY 1ab96a171faeeee38496d8b330771a7a
    CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234
    READ 335c4c6028171cfddfbaae1a9c313c52
    READ 3400330d1dfc7f3f7f4b8d4d803dfcf6
    Journal file

    View Slide

  110. libcore.io.DiskLruCache
    1
    100
    2
    CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054
    DIRTY 335c4c6028171cfddfbaae1a9c313c52
    CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342
    REMOVE 335c4c6028171cfddfbaae1a9c313c52
    DIRTY 1ab96a171faeeee38496d8b330771a7a
    CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234
    READ 335c4c6028171cfddfbaae1a9c313c52
    READ 3400330d1dfc7f3f7f4b8d4d803dfcf6
    Journal file

    View Slide

  111. libcore.io.DiskLruCache
    1
    100
    2
    CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054
    DIRTY 335c4c6028171cfddfbaae1a9c313c52
    CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342
    REMOVE 335c4c6028171cfddfbaae1a9c313c52
    DIRTY 1ab96a171faeeee38496d8b330771a7a
    CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234
    READ 335c4c6028171cfddfbaae1a9c313c52
    READ 3400330d1dfc7f3f7f4b8d4d803dfcf6
    Journal file

    View Slide

  112. Key
    Get
    Cache read flow

    View Slide

  113. Key
    Get
    Initialised
    ?
    Cache read flow

    View Slide

  114. Key
    Get
    Initialised
    ?
    No
    Initialisation
    Cache read flow

    View Slide

  115. Key
    Get
    Initialised
    ?
    No
    Journal File
    Initialisation
    Cache read flow

    View Slide

  116. Key
    Get
    Initialised
    ?
    No
    Journal File
    Initialisation
    LinkedHashMap
    Entry>
    Cache read flow

    View Slide

  117. Key
    Get
    Initialised
    ?
    Yes
    No
    Journal File
    Initialisation
    Get the Entry
    from cache
    LinkedHashMap
    Entry>
    Cache read flow

    View Slide

  118. Key
    Get
    Initialised
    ?
    Yes
    No
    Journal File
    Initialisation
    Get the Entry
    from cache
    LinkedHashMap
    Entry>
    Key
    Cache read flow

    View Slide

  119. Key
    Get
    Initialised
    ?
    Yes
    No
    Journal File
    Initialisation
    Get the Entry
    from cache
    LinkedHashMap
    Entry>
    Entry?
    Key
    Cache read flow

    View Slide

  120. Key
    Get
    Initialised
    ?
    Yes
    No
    Journal File
    Initialisation
    Get the Entry
    from cache
    LinkedHashMap
    Entry>
    Entry?
    Key
    Cache read flow

    View Slide

  121. Key
    Get
    Initialised
    ?
    Yes
    No
    Journal File
    Initialisation
    Get the Entry
    from cache
    LinkedHashMap
    Entry>
    Entry?
    Journal
    cleanup
    req?
    Key
    Cache read flow

    View Slide

  122. Key
    Get
    Initialised
    ?
    Yes
    No
    Journal File
    Initialisation
    Get the Entry
    from cache
    LinkedHashMap
    Entry>
    Entry?
    Journal
    cleanup
    req?
    No
    Return Snapshot?
    Key
    Cache read flow

    View Slide

  123. Key
    Get
    Initialised
    ?
    Yes
    No
    Journal File
    Initialisation
    Get the Entry
    from cache
    LinkedHashMap
    Entry>
    Entry?
    Journal
    cleanup
    req?
    Yes Run cleanup
    task
    No
    Return Snapshot?
    Key
    Cache read flow

    View Slide

  124. Key
    Get
    Initialised
    ?
    Yes
    No
    Journal File
    Initialisation
    Get the Entry
    from cache
    LinkedHashMap
    Entry>
    Entry?
    Journal
    cleanup
    req?
    Yes Run cleanup
    task
    No
    Return Snapshot?
    Key
    Cache read flow

    View Slide

  125. Commit
    Editor
    Cache write flow

    View Slide

  126. Initialised
    ?
    Commit
    Editor
    Cache write flow

    View Slide

  127. Initialised
    ?
    No
    Initialisation
    Commit
    Editor
    Cache write flow

    View Slide

  128. Initialised
    ?
    No
    Journal File
    Initialisation
    Commit
    Editor
    Cache write flow

    View Slide

  129. Initialised
    ?
    No
    Journal File
    Initialisation
    LinkedHashMap
    Entry>
    Commit
    Editor
    Cache write flow

    View Slide

  130. Initialised
    ?
    Yes
    No
    Journal File
    Initialisation
    Copy dirty
    file to clean
    file
    LinkedHashMap
    Entry>
    Commit
    Editor
    Cache write flow

    View Slide

  131. Initialised
    ?
    Yes
    No
    Journal File
    Initialisation
    Copy dirty
    file to clean
    file
    LinkedHashMap
    Entry>
    Commit
    Editor
    Cache write flow
    Key

    View Slide

  132. Initialised
    ?
    Yes
    No
    Journal File
    Initialisation
    Copy dirty
    file to clean
    file
    LinkedHashMap
    Entry>
    Commit
    Editor
    Cache write flow
    Key
    Entry

    View Slide

  133. Initialised
    ?
    Yes
    No
    Journal File
    Initialisation
    LinkedHashMap
    Entry>
    Copy dirty
    file to clean
    file
    Commit
    Editor
    Cache write flow
    Key
    Entry

    View Slide

  134. Cache
    full?
    Initialised
    ?
    Yes
    No
    Journal File
    Initialisation
    LinkedHashMap
    Entry>
    Copy dirty
    file to clean
    file
    Commit
    Editor
    Cache write flow
    Key
    Entry

    View Slide

  135. Cache
    full?
    Initialised
    ?
    Yes
    No
    Journal File
    Initialisation
    LinkedHashMap
    Entry>
    Copy dirty
    file to clean
    file
    Commit
    Editor
    Yes Run cleanup
    task
    Cache write flow
    Key
    Entry

    View Slide

  136. In memory caching

    View Slide

  137. In memory caching
    ● Strong Memory Cache

    View Slide

  138. In memory caching
    ● Strong Memory Cache
    ● Weak Memory Cache

    View Slide

  139. Engine
    Interceptor

    View Slide

  140. Engine
    Interceptor
    Is in strong
    memory?
    Key

    View Slide

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

    View Slide

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

    View Slide

  143. 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

    View Slide

  144. 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

    View Slide

  145. Strong Memory Cache
    ● Backed by LRU cache

    View Slide

  146. Strong Memory Cache
    ● Backed by LRU cache
    ● Size of the cache is computed dynamically

    View Slide

  147. Weak Memory Cache
    ● Backed by HashMap

    View Slide

  148. Weak Memory Cache
    ● Backed by HashMap
    ● Periodically do cleanups after 10 read or write
    operations

    View Slide

  149. Summary
    ● COIL - Coroutine Image Loader
    ● Modern, Easy, Lightweight and Fast
    ● API
    ● Image loading pipeline
    ● Caching

    View Slide

  150. Resources
    ● Library documentation
    https://coil-kt.github.io/coil/
    ● Github
    https://github.com/coil-kt/coil

    View Slide

  151. Thank you!

    View Slide

  152. Questions?

    View Slide