Amol Pawar

Function Type Variance

How Covariance and Contravariance Work in Kotlin’s Function Types

Kotlin’s function type variance is an important concept that helps developers understand how types behave when dealing with function inputs and outputs. If you’ve ever wondered why function parameters and return types follow different variance rules, this post will clear things up..! Understanding Variance in Kotlin Variance determines how subtyping relationships work in a type hierarchy....

Membership Required

You must be a member to access this content.

View Membership Levels

Already a member? Log in here
Kotlin Contravariance

Kotlin Contravariance Explained: Understanding Reversed Subtyping

Kotlin has a robust type system, but one of the trickiest concepts to grasp is contravariance. If you’ve ever scratched your head wondering how contravariance works and why it’s useful, you’re in the right place. This blog will break it down in simple terms with examples so you can fully understand Kotlin contravariance and use...

Membership Required

You must be a member to access this content.

View Membership Levels

Already a member? Log in here
fold and filter Functions in Kotlin

Mastering fold and filter Functions in Kotlin: A Comprehensive Guide

Kotlin provides powerful collection functions that make data manipulation intuitive and efficient. Among them, fold and filter stand out as essential tools for transforming and processing collections. In this guide, we’ll explore these functions in depth, providing detailed explanations and practical examples to help you leverage their full potential. Understanding the fold Function in Kotlin The...

Membership Required

You must be a member to access this content.

View Membership Levels

Already a member? Log in here
Coroutine Dispatcher in Kotlin

Coroutine Dispatchers in Kotlin: When to Use Dispatchers.IO, Main, Default, and Unconfined

Kotlin Coroutines make asynchronous programming simpler and more efficient, but choosing the right dispatcher is crucial for performance and responsiveness. In this guide, we’ll explore Coroutine Dispatchers in Kotlin, focusing on Dispatchers.IO, Dispatchers.Main, Dispatchers.Default, and Dispatchers.Unconfined—when to use each, how they work, and best practices. What Are Coroutine Dispatchers in Kotlin? Coroutine Dispatchers determine the thread...

Membership Required

You must be a member to access this content.

View Membership Levels

Already a member? Log in here
kotlin flow

Kotlin Flow: A Deep Dive into Reactive Streams in Kotlin

In modern Android and Kotlin development, handling asynchronous data streams efficiently is crucial. Whether you’re working with API responses, user input events, or real-time updates, Kotlin Flow provides a powerful, coroutine-based solution. In this guide, we’ll explore Kotlin Flow in-depth, covering its concepts, operators, builders, real-world use cases, and best practices.

What is Kotlin Flow?

Kotlin Flow is a cold, asynchronous, and reactive stream API introduced as part of Kotlin Coroutines. It is designed to handle sequential data streams efficiently, making it a great alternative to RxJava and LiveData.

Key Characteristics of Flow

  • Cold Stream — A Flow only starts emitting values when it is collected.
  • Sequential Execution — Emissions, transformations, and collections occur one after another.
  • Backpressure Support — Unlike RxJava, Flow automatically handles backpressure.
  • Coroutine Friendly — Works seamlessly with Kotlin Coroutines.

Basic Example of Flow

Kotlin
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.runBlocking

fun simpleFlow(): Flow<Int> = flow {
    for (i in 1..5) {
        emit(i)  // Emitting values one by one
    }
}

fun main() = runBlocking {
    simpleFlow().collect { value -> println(value) }
}

Output:

Kotlin
1
2
3
4
5

Use Flow when dealing with data streams that require coroutine support and backpressure handling.

Flow Builders

1. flow {} – Custom Flow Creation

Kotlin
val customFlow: Flow<Int> = flow {
    for (i in 1..3) {
        emit(i)  // Emit values
    }
}

2. flowOf() – Flow from Fixed Values

Kotlin
val numbersFlow = flowOf(1, 2, 3, 4, 5)

3. asFlow() – Convert Collections to Flow

Kotlin
val listFlow = listOf(1, 2, 3).asFlow()

Transforming Flow Data with Operators

1. map {} – Transform Each Element

Kotlin
simpleFlow().map { it * 2 }.collect { println(it) }

Output: 2, 4, 6, 8, 10

2. filter {} – Filter Elements

Kotlin
simpleFlow().filter { it % 2 == 0 }.collect { println(it) }

Output: 2, 4

3. collectLatest {} – Cancel Previous Collection

Kotlin
simpleFlow().collectLatest { value ->
    println("Processing $value")
}

4. flatMapConcat {} – Sequential Mapping

Kotlin
val flow1 = flowOf(1, 2, 3)
flow1.flatMapConcat { value -> flowOf(value * 10) }
    .collect { println(it) }

Output: 10, 20, 30

Handling Flow Cancellation & Exceptions

1. Cancelling a Flow

Kotlin
val job = launch {
    simpleFlow().collect { println(it) }
}
delay(2000)
job.cancel()  // Cancels the Flow

2. Handling Exceptions

Kotlin
flow {
    emit(1)
    throw RuntimeException("Error!")
}.catch { e -> println("Caught: ${e.message}") }
 .collect { println(it) }

StateFlow & SharedFlow

StateFlow — Holds a State

StateFlow is similar to LiveData and is used to store a single state that updates over time.

Kotlin
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

fun main() = runBlocking {
    val stateFlow = MutableStateFlow(0)

    val job = launch {
        stateFlow.collect { value ->
            println("Collector received: $value")
        }
    }

    delay(500)
    stateFlow.value = 1
    delay(500)
    stateFlow.value = 2
    delay(500)
    job.cancel()
}


//Output

Collector received: 0
Collector received: 1
Collector received: 2

StateFlow always emits the latest value to collectors. It behaves like LiveData, and collectors receive the current state immediately upon subscription.

SharedFlow — Broadcasts Data to Multiple Collectors

Kotlin
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

fun main() = runBlocking {
    // Create a MutableSharedFlow with a buffer capacity of 2
    val sharedFlow = MutableSharedFlow<Int>(
        replay = 0,
        extraBufferCapacity = 2
    )

    val job1 = launch {
        sharedFlow.collect { value ->
            println("Collector 1 received: $value")
        }
    }

    val job2 = launch {
        sharedFlow.collect { value ->
            println("Collector 2 received: $value")
        }
    }

    // Delay to ensure collectors are active before emitting
    delay(100)

    sharedFlow.emit(10)
    sharedFlow.emit(20)

    delay(500)

    job1.cancel()
    job2.cancel()
}

// Output

Collector 1 received: 10
Collector 2 received: 10
Collector 1 received: 20
Collector 2 received: 20

By default, MutableSharedFlow has no buffer and replay = 0, meaning it won’t emit any value unless a collector is ready at the moment of emission.

  • We set extraBufferCapacity = 2, allowing SharedFlow to buffer a couple of values while the collectors start.
  • We add delay(100) before emitting, ensuring both collectors are already collecting.

This way, both collectors reliably receive all values.

SharedFlow broadcasts emitted values to all active collectors. It’s great for one-time events (like navigation, snackbars, etc.), and multiple collectors will receive the same emissions.

When to Use Kotlin Flow?

  • Fetching API data periodically
  • Streaming real-time UI updates
  • Handling user input events
  • Data transformation pipelines

Conclusion

Kotlin Flow is a modern, efficient, and coroutine-friendly way to handle asynchronous data streams. By using Flow builders, operators, exception handling, and StateFlow/SharedFlow, developers can build scalable, efficient applications.

Coroutine Scopes

Why Coroutine Scopes Matter: A Deep Dive into Kotlin’s Concurrency Model

Kotlin’s coroutines have revolutionized asynchronous programming by making concurrency more manageable and readable. But to truly harness their power, understanding Coroutine Scopes is essential. In this guide, we’ll break down what Coroutine Scopes are, why they matter, and how they fit into Kotlin’s concurrency model. What Are Coroutine Scopes? A Coroutine Scope defines the lifecycle...

Membership Required

You must be a member to access this content.

View Membership Levels

Already a member? Log in here
Use-Site Variance

Use-Site Variance in Kotlin Explained: When & How It Works

Kotlin is a powerful and flexible programming language that introduces many advanced features to make development easier. One such feature is Use-Site Variance in Kotlin, which helps handle type variance effectively in generic programming. If you’ve ever struggled with understanding variance in Kotlin, this guide will break it down in a simple, easy-to-understand way. What...

Membership Required

You must be a member to access this content.

View Membership Levels

Already a member? Log in here
Kotlin StateFlow and SharedFlow

Kotlin StateFlow and SharedFlow Explained: A Beginner-Friendly Guide

Kotlin’s Flow API has transformed the way we think about asynchronous data streams. But when your app needs to hold state or broadcast events, two specialized types of Flows shine the brightest: StateFlow and SharedFlow.

In this guide, we’ll break down StateFlow and SharedFlow in a simple way. Whether you’re working with Jetpack Compose, MVVM, or traditional Android UI, you’ll understand when and how to use each one — with examples.

StateFlow — Holds a State

StateFlow is similar to LiveData and is used to store a single state that updates over time.

Kotlin
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

fun main() = runBlocking {
    val stateFlow = MutableStateFlow(0)

    val job = launch {
        stateFlow.collect { value ->
            println("Collector received: $value")
        }
    }

    delay(500)
    stateFlow.value = 1
    delay(500)
    stateFlow.value = 2
    delay(500)
    job.cancel()
}


//Output

Collector received: 0
Collector received: 1
Collector received: 2

StateFlow always emits the latest value to collectors. It behaves like LiveData, and collectors receive the current state immediately upon subscription.

SharedFlow — Broadcasts Data to Multiple Collectors

Kotlin
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

fun main() = runBlocking {
    // Create a MutableSharedFlow with a buffer capacity of 2
    val sharedFlow = MutableSharedFlow<Int>(
        replay = 0,
        extraBufferCapacity = 2
    )

    val job1 = launch {
        sharedFlow.collect { value ->
            println("Collector 1 received: $value")
        }
    }

    val job2 = launch {
        sharedFlow.collect { value ->
            println("Collector 2 received: $value")
        }
    }

    // Delay to ensure collectors are active before emitting
    delay(100)

    sharedFlow.emit(10)
    sharedFlow.emit(20)

    delay(500)

    job1.cancel()
    job2.cancel()
}

// Output

Collector 1 received: 10
Collector 2 received: 10
Collector 1 received: 20
Collector 2 received: 20

By default, MutableSharedFlow has no buffer and replay = 0, meaning it won’t emit any value unless a collector is ready at the moment of emission.

  • We set extraBufferCapacity = 2, allowing SharedFlow to buffer a couple of values while the collectors start.
  • We add delay(100) before emitting, ensuring both collectors are already collecting.

This way, both collectors reliably receive all values.

SharedFlow broadcasts emitted values to all active collectors. It’s great for one-time events (like navigation, snackbars, etc.), and multiple collectors will receive the same emissions.

Conclusion

Kotlin’s StateFlow and SharedFlow are powerful tools to build reactive UIs that are predictable, scalable, and cleanly architected. Understanding the difference between state and event helps you choose the right flow for the right situation.

How CSS Cascading Works

How Does the CSS Cascading Work? Priority Rules Explained Simply

When you’re styling a website, you might run into a situation where multiple CSS rules target the same element. Which one wins? This is where understanding how CSS cascading works becomes essential. We’re going to make this easy. No confusing tech-speak, just clear and real examples that make sense. If you’ve ever wondered why some...

Membership Required

You must be a member to access this content.

View Membership Levels

Already a member? Log in here
Minify HTML

Minify HTML for Better SEO and Core Web Vitals: Here’s How

When it comes to SEO, every millisecond counts. That’s why web performance is a big deal — especially now that Google uses Core Web Vitals as a ranking factor. One of the easiest, most effective ways to improve your site speed? Minify HTML. In this post, we’ll walk you through what minifying HTML actually means, why it...

Membership Required

You must be a member to access this content.

View Membership Levels

Already a member? Log in here
error: Content is protected !!