Kotlin Coroutines:
Deep Dive

Kotlin coroutines have revolutionized JVM development, especially on Android and the backend, as they let us easily implement efficient and reliable multithreading. Their cutting-edge design and features are ideally suited to modern use cases. In this book, we will explore how Kotlin coroutines work and how we can use them to improve our applications – using both the built-in support and the kotlinx.coroutines library.
This is a practical book. It shows everything with examples and focuses on real-life use cases. As this technology is already widely used on Android and backend applications, we will see how we can use it there and what the best practices are.
The purpose

The importance of concurrency is growing, but the classic techniques are not enough. Current trends suggest that coroutines are where our industry is clearly heading, and Kotlin coroutines are a very solid step in the right direction. Let me show them to you, with examples of how well they help in common use cases. I hope you will have a lot of fun reading this book.
Chapter by Chapter
Clear path to progress
- Who is this book for?
- The structure of this book
- What will be covered?
- The Kotlin for Developers series
- Conventions
- Code conventions
- Version
- Exercises and solutions
- Acknowledgments
- Simplicity
- Performance
- Cancellation
- Synchronization
- Testability
- Flow
- Coroutines are multiplatform
- The biggest problem with Kotlin Coroutines
- Summary
- Real-life usages
- Exercise: Factorial sequence
- Exercise: Prime numbers sequence
- A game analogy
- Suspending functions
- Your first suspension
- What is stored in the continuation?
- Delaying a coroutine
- Resuming with a value
- Resume with an exception
- Suspending a coroutine, not a function
- Summary
- Exercise: Callback function wrappers
- Exercise: Continuation storage
- Continuation-passing style
- A very simple function
- A function with a state
- A function resumed with a value
- The call stack
- Suspending functions in other contexts
- The actual code
- The performance of suspending functions
- Summary
- Exercise: What is stored by a continuation?
- Asynchronous coroutine builders
- Blocking coroutine builders
- Structured Concurrency
- Coroutine scope functions
- Summary
- Exercise: UserDetailsRepository
- Exercise: BestStudentUseCase
- Exercise: CommentService
- Exercise: mapAsync
- CoroutineContext interface
- Finding elements in CoroutineContext
- Adding contexts
- Empty coroutine context
- Subtracting elements
- Folding context
- Coroutine context and builders
- Accessing context in a suspending function
- Changing context in suspending functions
- Creating our own context
- Coroutines and thread elements
- Summary
- Exercise: Understanding context propagation
- Exercise: CounterContext
- Default dispatcher
- Limiting the default dispatcher
- Main dispatcher
- IO dispatcher
- Dispatcher with a custom limit
- Dispatcher with a fixed pool of threads
- Dispatcher limited to a single thread
- Using virtual threads from Project Loom
- Unconfined dispatcher
- Immediate main dispatching
- Continuation interceptor
- Performance of dispatchers when executing different tasks
- Summary
- Exercise: Using dispatchers
- Exercise: DiscNewsRepository
- Exercise: Experiments with dispatchers
- Job and relationships
- Coroutine lifecycle
- Awaiting job completion
- The Job factory function
- Synchronizing coroutines
- Summary
- Basic cancellation
- The finally block
- invokeOnCompletion
- Cancellation of children
- Cancellation in a coroutine scope
- Just one more call
- Stopping the unstoppable
- CancellationException is special
- CancellationException does not propagate to its parent
- withTimeout
- suspendCancellableCoroutine
- Summary
- Exercise: Correct mistakes with cancellation
- Exceptions and structured concurrency
- SupervisorJob
- supervisorScope
- Exceptions and await call
- CoroutineExceptionHandler
- Summary
- CoroutineScope factory function
- Constructing a background scope
- Constructing a scope on Android
- Summary
- Exercise: NotificationSender
- Exercise: BaseViewModel
- Using atomic values
- Synchronized blocks
- Using a dispatcher limited to a single thread
- Mutex
- Semaphore
- Summary
- Exercise: CompanyDetailsRepository
- Exercise: CancellingRefresher
- Exercise: TokenRepository
- Exercise: Suspended lazy
- Exercise: mapAsync with concurrency limit
- Testing time dependencies
- TestCoroutineScheduler and StandardTestDispatcher
- runTest
- Background scope
- Testing cancellation and context passing
- UnconfinedTestDispatcher
- Using mocks
- Testing functions that change a dispatcher
- Testing what happens during function execution
- Testing functions that launch new coroutines
- Testing classes that need scope in runTest
- Replacing the main dispatcher
- Testing Android functions that launch coroutines
- Setting a test dispatcher with a rule
- Summary
- Exercise: Test UserDetailsRepository
- Exercise: Testing mapAsync
- Exercise: Testing the NotificationSender class
- Exercise: Testing a View Model
- Channel types
- On buffer overflow
- On undelivered element handler
- Fan-out
- Fan-in
- Pipelines
- Practical usage
- Summary
- Exercise: UserRefresher
- Exercise: Cafeteria simulation
- Selecting deferred values
- Selecting from channels
- Summary
- Exercise: raceOf
- Hot vs cold
- Hot channels, cold flow
- Summary
- Comparing flow to other ways of representing values
- The characteristics of Flow
- Flow nomenclature
- Real-life use cases
- Summary
- Understanding Flow
- How Flow processing works
- Flow is synchronous
- Flow and shared state
- Conclusion
- Flow from raw values
- Converters
- Converting a function to a flow
- Flow and Reactive Streams
- Flow builders
- Understanding flow builder
- channelFlow
- callbackFlow
- Summary
- Exercise: Flow utils
- Exercise: All users flow
- Exercise: distinct
- onEach
- onStart
- onCompletion
- onEmpty
- catch
- Uncaught exceptions
- retry
- flowOn
- launchIn
- Summary
- Exercise: TemperatureService
- Exercise: NewsViewModel
- map
- filter
- take and drop
- How does collection processing work?
- merge, zip and combine
- fold and scan
- flatMapConcat, flatMapMerge and flatMapLatest
- Distinct until changed
- buffer and conflate
- debounce
- sample
- Terminal operations
- Summary
- Exercise: ProductService
- Exercise: Flow Kata
- Exercise: MessageService
- SharedFlow
- shareIn
- StateFlow
- stateIn
- Summary
- Exercise: Update ProductService
- Exercise: Update TemperatureService
- Exercise: LocationService
- Exercise: PriceService
- Exercise: NewsViewModel using stateIn
- Transformation functions
- Testing infinite flows
- Determining how many connections were opened
- Testing view models
- Summary
- Exercise: Flow testing
- Data/Adapters Layer
- Domain Layer
- Presentation/API/UI layer
- Summary
- Threads on different platforms
- Transforming suspending into non-suspending functions
- Calling suspending functions from other languages
- Flow and Reactive Streams
- Summary
- Best practices