Blog Infos
Author
Published
Topics
, , , ,
Published

 

Ever had a fast data source send more items than your app can handle, causing slowdowns or even crashes? Kotlin Flow gives you built-in ways to keep your producer and consumer in step. In this post, we’ll cover:

  1. What backpressure means
  2. How Flow’s default “wait for each other” mode works
  3. When to add a small queue with buffer()
  4. How conflate() skips old items
  5. Why collectLatest { } stops old work on new data
  6. How to pick the right option for your case
What Backpressure Means

Backpressure is simply making sure a fast sender of data doesn’t overwhelm a slower receiver. Without it, you might end up storing too many items in memory or wasting time working on out-of-date information.

Backpressure helps you:

  • Keep memory use under control
  • Avoid doing unnecessary work
  • Make app performance more predictable
1. Default “Wait for Each Other” Mode

By default, when you do:

flow {
  repeat(3) {
    emit(it)
    println("Sent $it")
    delay(100)            // fast sender
  }
}
.collect { value ->
  println("Handling $value")
  delay(300)             // slow handler
}

the sender (emit) will pause until the handler (collect) finishes with the last value. There’s no queue, each value is sent and handled one at a time.

2. Adding a Small Queue with buffer()

If you want the sender to get ahead by a bit, use:

flow { … }
  .buffer(capacity = 2)
  .collect { value ->
    // slow work here
  }
  • Now the sender can put up to 2 items into a little queue.
  • Once the queue is full, it will pause again.

This gives you a limited queue: you still handle every item, but you smooth out spikes in speed.

3. Skipping Old Items with conflate()

When you only care about the newest data, such as updating a progress bar, you can write:

flow { … }
  .conflate()
  .collect { value ->
    println("Update to $value")
    delay(300)
  }
  • If the handler is busy, only the latest unhandled item is kept.
  • Older ones are dropped, so you never process stale updates.

Note: conflate() does not stop the current work; it just skips old values next time you read.

4. Stopping Old Work with collectLatest { }

To go further and cancel any ongoing work when new data comes in, use:

flow { … }
  .collectLatest { value ->
    println("Start $value")
    delay(300)    // might get cut off
    println("Done $value")
  }
  • On each new emit, the block handling the previous value is thrown away right away.
  • You only finish the work for the very last value if the sender keeps sending faster than you can handle.

This is perfect for search-as-you-type, where you want to drop old requests as soon as the user types again.

5. Choosing the Right Tool
  • Plain collect
    What it does: Sender and handler wait on each other, one by one
    When to pick it: You must handle every item in order
  • .buffer(n)
    What it does: Small queue of size n; no items are dropped
    When to pick it: You want a little burst of buffering but still process all items
  • .conflate()
    What it does: Keep only the latest item if the handler is busy
    When to pick it: You need the freshest data but still want to finish your current work
  • collectLatest { }
    What it does: Cancel any ongoing work as soon as new data arrives
    When to pick it: Only the most recent result matters; drop everything else immediately

Job Offers

Job Offers

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

,

Tests unitaires avec KotlinFlow

Lorsque nous développons une fonctionnalité, nous devons écrire les tests unitaires. C’est une partie essentielle du développement. Cela assure le bon fonctionnement du code lors de futurs changements ou refactorisations. Kotlin Flow ne fait pas…
Watch Video

Tests unitaires avec KotlinFlow

Florent Blot
Android Developer
Geev

Tests unitaires avec KotlinFlow

Florent Blot
Android Developer
Geev

Tests unitaires avec KotlinFlow

Florent Blot
Android Developer
Geev

Jobs

6. Final Thoughts
  • Backpressure keeps fast data streams from overloading slow processors.
  • Default mode has no queue: safe but can be slow.
  • buffer() adds a small queue: more flexibility, no drops.
  • conflate() skips old values: always fresh, but let current work finish.
  • collectLatest { } stops old work: only finish the latest item.

Next time your Flow seems too fast or too slow, ask yourself:

  1. Do I need to handle every value?
  2. Would a small queue help?
  3. Is only the newest data important?
  4. Should I cancel old work when new data arrives?

Pick the simplest option that fits, and Kotlin Flow will handle the rest.

This article was previously published on proandroiddev.com.

Menu