Android

Hashing in Cryptography

A Deep Dive into Hashing in Cryptography: Functions, Uses, and Risks

If you’ve ever stored a password online, you’ve already relied on hashing — even if you didn’t know it. Hashing in cryptography is a fundamental security tool that turns your data into a fixed-size, irreversible code.

In this guide, we’ll unpack what hashing is, how it works, why it’s used, and the risks you need to be aware of. We’ll even look at some Kotlin code so you can see it in action.

What Is Hashing in Cryptography?

Hashing in cryptography is the process of taking any piece of data — like text, files, or numbers — and running it through a special algorithm (called a hash function) to produce a fixed-size string of characters known as a hash value or digest.

A good cryptographic hash function has four main properties:

  1. Deterministic — The same input will always produce the same hash.
  2. Fast computation — It should generate the hash quickly.
  3. Irreversible — You cannot reconstruct the original data from the hash.
  4. Collision resistance — Two different inputs shouldn’t produce the same hash.

How Hash Functions Work

Imagine hashing as a digital fingerprint for data. You input a file or message, and out pops a unique fingerprint (the hash). Even the slightest tweak to the input radically alters the fingerprint, making it easy to detect unauthorized changes.

The hash function processes input in blocks, compresses data, and applies complex transformations to generate the fixed-length hash. Popular algorithms include SHA-256, SHA-512, MD5 (though this is now weak and not recommended), and newer schemes like SHA-3.

Why Use Hashing in Cryptography?

Here’s where hashing shines:

  • Password storage — Websites store hashed passwords instead of plain text.
  • Data integrity checks — Verifying that files haven’t been altered.
  • Digital signatures — Ensuring authenticity and non-repudiation.
  • Blockchain — Securing and linking blocks of transactions.

A Kotlin Example: SHA-256 Hashing

Let’s write a simple Kotlin program that hashes a string using SHA-256.

Kotlin
import java.security.MessageDigest

fun hashSHA256(input: String): String {
    // Create a MessageDigest instance for SHA-256
    val bytes = MessageDigest.getInstance("SHA-256")
        .digest(input.toByteArray())
    // Convert the byte array to a readable hex string
    return bytes.joinToString("") { "%02x".format(it) }
}

fun main() {
    val text = "Hello, Hashing!"
    val hashValue = hashSHA256(text)
    println("Original Text: $text")
    println("SHA-256 Hash: $hashValue")
}

Here,

  1. MessageDigest.getInstance("SHA-256")
     This creates an object that can compute SHA-256 hashes.
  2. .digest(input.toByteArray())
     Converts the string into bytes and hashes it.
  3. joinToString("") { "%02x".format(it) }
     Formats each byte into a two-character hexadecimal string and joins them into one long hash.

When you run this code, you’ll see a 64-character hexadecimal string — the SHA-256 hash of "Hello, Hashing!".

Risks and Limitations of Hashing

Hashing is powerful, but it’s not bulletproof.

  1. Collision attacks — Rare but possible; two different inputs could produce the same hash.
  2. Rainbow tables — Precomputed tables that map hashes back to possible passwords.
  3. Brute force attacks — Trying every possible input until the hash matches.

Best practice: Always use hashing with salts (random data added to the input) for password storage to defend against rainbow tables.

Best Practices for Using Hashing in Cryptography

  • Use proven algorithms (e.g., SHA-256, SHA-3, BLAKE2).
  • For passwords, use slow, salted hash functions like bcrypt, scrypt, or Argon2.
  • Never store plain text passwords.
  • Regularly update to stronger hashing algorithms as standards evolve.

Conclusion

Hashing in cryptography is like a digital fingerprint system — simple in concept but critical for security. It ensures data integrity, safeguards passwords, and powers technologies like blockchain.

While hashing isn’t a silver bullet against every cyber threat, when implemented with modern algorithms and best practices, it’s one of the most reliable security layers we have.

Kotlin Flow

Kotlin Flow vs LiveData: Why Android Developers Are Moving On (And How to Migrate Smoothly)

If you’ve been building Android apps for a few years, you’ve probably written your fair share of LiveData. For a long time, it was the go-to choice for exposing observable data from a ViewModel to the UI. It solved an important problem: lifecycle awareness.

But the Android world has changed. Kotlin coroutines have become the default for async programming, and along with them, Flow and StateFlow have emerged as powerful, coroutine-native reactive streams. Many developers are now replacing LiveData entirely.

In this article, I’ll explain why the shift is happening, what makes Flow and StateFlow better in modern Android development, and give you a practical, code-focused migration guide that won’t break your existing architecture.

LiveData’s Origin and Limitations

LiveData was introduced back in 2017 as part of Android Architecture Components. At that time:

  • Kotlin coroutines were experimental.
  • Most apps used callbacks or RxJava for reactive streams.
  • We needed something lifecycle-aware to avoid leaks and crashes from background updates.

LiveData solved these problems well for the time, but it has some hard limitations:

  • It’s Android-specific (not usable in Kotlin Multiplatform projects).
  • It has very few transformation operators (map, switchMap).
  • Integration with coroutines feels bolted on via adapters.
  • You can’t use it directly in non-UI layers without bringing in Android dependencies.

Why Flow and StateFlow are Taking Over

Flow is platform-agnostic

Flow comes from the kotlinx.coroutines library — meaning it works in Android, server-side Kotlin, desktop apps, and KMP projects. It’s not tied to the Android lifecycle or framework.

Rich operator support

Flow offers powerful operators like map, filter, combine, debounce, retry, flatMapLatest, and more. These allow you to build complex data pipelines with minimal boilerplate.

Kotlin
repository.getUsersFlow()
    .debounce(300)
    .map { users -> users.filter { it.isActive } }
    .flowOn(Dispatchers.IO)
    .collect { activeUsers ->
        // Update UI
    }

Doing this in LiveData would be awkward at best.

Coroutine-native

Flow integrates directly with coroutines:

  • You can collect it in a coroutine scope.
  • Context switching is built in (flowOn).
  • Structured concurrency ensures proper cleanup.

LiveData requires a bridge (asLiveData or liveData {}) to fit into coroutine-based code.

Lifecycle awareness without coupling

While Flow itself isn’t lifecycle-aware, you can make it so with repeatOnLifecycle or launchWhenStarted:

Kotlin
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.dataFlow.collect { data ->
            render(data)
        }
    }
}

This cancels the collection automatically when the UI stops, just like LiveData.

Works for hot and cold streams

  • Cold streams: Only emit when collected (default Flow behavior).
  • Hot streams: Always active, emit latest values (StateFlow, SharedFlow).

LiveData is always “hot” and always keeps the last value.

Why Google is Leaning Toward Flow

Many Jetpack libraries have switched to Flow-first APIs:

  • Room: Can return Flow<T> directly.
  • DataStore: Uses Flow for reading values.
  • Paging 3: Exposes Flow<PagingData<T>> as the default.

The trend is clear — Flow is becoming the reactive backbone of Android development.

StateFlow: The Modern LiveData

For most UI state, the direct replacement for LiveData is StateFlow:

  • Always holds a current value (.value).
  • Hot stream — new collectors get the latest value instantly.
  • Fully coroutine-native.

With a small helper like repeatOnLifecycle, you get the same lifecycle safety as LiveData, but with more control and flexibility.

Migration Guide: LiveData → StateFlow

Basic property migration

Before (LiveData):

Kotlin
private val _name = MutableLiveData<String>()
val name: LiveData<String> = _name

After (StateFlow):

Kotlin
private val _name = MutableStateFlow("")
val name: StateFlow<String> = _name

Observing in the UI

Before:

Kotlin
viewModel.name.observe(viewLifecycleOwner) { name ->
    binding.textView.text = name
}

After:

Kotlin
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.name.collect { name ->
            binding.textView.text = name
        }
    }
}

Transformations

map:

Kotlin
val upperName: StateFlow<String> =
    name.map { it.uppercase() }
        .stateIn(viewModelScope, SharingStarted.Eagerly, "")

switchMapflatMapLatest:

Kotlin
val user: StateFlow<User?> =
    userId.flatMapLatest { id ->
        repository.getUserFlow(id)
    }.stateIn(viewModelScope, SharingStarted.Lazily, null)

MediatorLiveData → combine

Kotlin
val combined: StateFlow<Pair<String, Int>> =
    combine(name, age) { n, a -> n to a }
        .stateIn(viewModelScope, SharingStarted.Eagerly, "" to 0)

SingleLiveEvent → SharedFlow

Kotlin
private val _events = MutableSharedFlow<String>()
val events: SharedFlow<String> = _events

fun sendEvent(msg: String) {
    viewModelScope.launch { _events.emit(msg) }
}

UI:

Kotlin
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.events.collect { showSnackbar(it) }
    }
}

Best Practices

  • Use StateFlow for UI state, SharedFlow for events.
  • Wrap mutable flows in immutable StateFlow/SharedFlow when exposing from ViewModel.
  • Always collect flows inside repeatOnLifecycle in UI components to avoid leaks.
  • For background layers, use Flow freely without lifecycle bindings.

Conclusion

LiveData isn’t “bad” — it still works fine for many apps. But the Android ecosystem has moved on. With coroutines and Flow, you get a unified, powerful, cross-platform reactive framework that covers more cases with less friction.

If you start new projects today, building with Flow and StateFlow from the ground up will keep your architecture modern and future-proof. And if you’re migrating an existing app, the step-by-step transformations above should make it painless.

Encryption Basics

Encryption Basics: What It Is and How It Secures Your Digital Life

In today’s digital world, encryption is one of the most important tools protecting our privacy and data security. Whether you’re sending messages, shopping online, or just browsing the web, encryption quietly works behind the scenes to keep your information safe from prying eyes.

In this blog, we’ll break down what encryption really means, why it matters, and how it keeps your digital life secure.

What Is Encryption?

At its core, encryption is the process of converting readable data into a coded format that only authorized people can decode and read. Think of it as a secret language that only you and the intended recipient understand.

Imagine writing a message in invisible ink. Anyone who sees the paper won’t understand your message unless they know the trick to reveal it. That’s exactly how encryption works — it scrambles your data so outsiders can’t make sense of it.

Why Is Encryption Important?

We live in an era where cyber attacks, hacking, and data breaches are common. Encryption is a key defense mechanism that helps protect:

  • Personal information: Your passwords, credit card numbers, and private messages.
  • Corporate data: Sensitive business information and customer data.
  • Government communications: Classified and confidential government documents.

Without encryption, all this data could be easily intercepted and read by unauthorized parties.

How Does Encryption Work?

Encryption uses a set of rules called an algorithm and a secret key to convert plain text (your original data) into ciphertext (the scrambled data). Only someone with the correct key can decrypt the ciphertext back to its original form.

Here’s a basic overview of the process:

  1. Plain Text: Your original message or data.
  2. Encryption Algorithm: The method used to scramble the data.
  3. Encryption Key: A secret piece of information that controls the scrambling.
  4. Cipher Text: The encrypted, unreadable data sent over networks.
  5. Decryption: Using a key and algorithm to convert ciphertext back to plain text.

Types of Encryption You Should Know

1. Symmetric Encryption

In symmetric encryption, the same key is used to encrypt and decrypt the data. It’s fast and efficient but requires both parties to securely share the key beforehand.

Example Algorithms: AES (Advanced Encryption Standard), DES (Data Encryption Standard)

2. Asymmetric Encryption

Also called public-key encryption, it uses two keys: a public key to encrypt data and a private key to decrypt it. This method solves the key-sharing problem but is slower than symmetric encryption.

Example Algorithms: RSA, ECC (Elliptic Curve Cryptography)

A Simple Encryption Example in Kotlin

If you’re curious about how encryption looks in Kotlin — a popular language for Android apps and beyond — here’s a straightforward example using AES symmetric encryption.

This code will encrypt and decrypt a message with a secret key.

Kotlin
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
import javax.crypto.spec.IvParameterSpec
import android.util.Base64

fun generateAESKey(): SecretKey {
    val keyGen = KeyGenerator.getInstance("AES")
    keyGen.init(128)  // AES key size (128 bits)
    return keyGen.generateKey()
}

fun encrypt(message: String, secretKey: SecretKey, iv: ByteArray): String {
    val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
    cipher.init(Cipher.ENCRYPT_MODE, secretKey, IvParameterSpec(iv))
    val encryptedBytes = cipher.doFinal(message.toByteArray(Charsets.UTF_8))
    return Base64.encodeToString(encryptedBytes, Base64.DEFAULT)
}

fun decrypt(encryptedMessage: String, secretKey: SecretKey, iv: ByteArray): String {
    val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
    cipher.init(Cipher.DECRYPT_MODE, secretKey, IvParameterSpec(iv))
    val decodedBytes = Base64.decode(encryptedMessage, Base64.DEFAULT)
    val decryptedBytes = cipher.doFinal(decodedBytes)
    return String(decryptedBytes, Charsets.UTF_8)
}

fun main() {
    val secretKey = generateAESKey()
    val iv = ByteArray(16) { 0 }  // Initialization Vector (usually random, but zeros here for simplicity)

    val originalMessage = "Hello, this is a secret message!"
    println("Original: $originalMessage")

    val encrypted = encrypt(originalMessage, secretKey, iv)
    println("Encrypted: $encrypted")

    val decrypted = decrypt(encrypted, secretKey, iv)
    println("Decrypted: $decrypted")
}

How This Code Works

  • Key Generation: generateAESKey() creates a random 128-bit AES secret key.
  • Encryption: The encrypt function takes your message, the secret key, and an Initialization Vector (IV), then encrypts the message with AES in CBC mode. The output is Base64 encoded for easy printing.
  • Decryption: The decrypt function reverses the process — it decodes Base64, decrypts the bytes, and converts them back to the original string.
  • Initialization Vector (IV): This is a fixed-size byte array used to add randomness and make each encryption unique. In real apps, it should be random and securely shared along with the ciphertext.

Where Do You Encounter Encryption in Daily Life?

  • Messaging Apps: Apps like WhatsApp and Signal use end-to-end encryption to keep your chats private.
  • Web Browsing: HTTPS encrypts the data between your browser and websites.
  • Online Banking: Banks encrypt your transactions to prevent fraud.
  • Cloud Storage: Services like Google Drive encrypt your files to keep them safe.

Conclusion

Encryption is more than just a technical buzzword — it’s the backbone of digital privacy and security. By understanding encryption basics, you can appreciate how your data is protected and why it’s critical to use secure apps and websites.

Next time you send a message or make an online purchase, remember encryption is working hard to keep your information safe — quietly, but effectively.

Cryptography

What Is Cryptography and How Does It Work? A Beginner’s Explanation

If you’ve ever entered a password, paid online, or chatted on WhatsApp, you’ve already used cryptography — whether you knew it or not.
 It’s the invisible lock protecting your private information from hackers and eavesdroppers.

In this beginner-friendly guide, you’ll learn what cryptography is, how it works, and see a Kotlin example in action.
 No complex math — just a clear explanation you can actually understand.

What Is Cryptography?

Cryptography is the science of securing information so only the intended people can read it.
 Think of it as putting your message in a sealed envelope, but one that only the right person has the key to open.

The term comes from the Greek words:

  • kryptos — hidden
  • graphein — writing

Put together: hidden writing.

Why Is Cryptography Important?

Without cryptography, sending data online would be like shouting your secrets in a crowded room.
 Here’s where it plays a role every day:

  • Online banking: Keeps credit card and transaction data safe.
  • Messaging apps: WhatsApp, Signal, and Telegram use strong end-to-end encryption.
  • Passwords: Stored securely so hackers can’t read them.
  • Data privacy: Protects personal files, medical records, and government documents.

The Core Principles of Cryptography

  1. Confidentiality — Only the intended person can read the message.
  2. Integrity — Ensures the message isn’t altered along the way.
  3. Authentication — Confirms the identity of sender and receiver.
  4. Non-repudiation — Prevents someone from denying they sent a message.

How Does Cryptography Work?

At a basic level, cryptography takes:

  • Plaintext — normal readable data
  • Key — a secret or public piece of information
  • Encryption algorithm — a method to scramble the plaintext

It turns plaintext into ciphertext (scrambled text).
 Only someone with the correct key can reverse the process through decryption.

Two Main Types of Cryptography

1. Symmetric Key Cryptography

  • Same key for encryption and decryption.
  • Faster but needs secure key sharing.
  • Example: AES (Advanced Encryption Standard).

2. Asymmetric Key Cryptography

  • Two keys: public (to encrypt) and private (to decrypt).
  • You can share the public key openly.
  • Example: RSA encryption.

Kotlin Example: Caesar Cipher

Let’s write a simple Caesar Cipher in Kotlin — one of the earliest encryption methods.
 It shifts letters in the alphabet by a fixed number.

Kotlin
fun encrypt(text: String, shift: Int): String {
    val result = StringBuilder()

    for (char in text) {
        if (char.isLetter()) {
            val base = if (char.isUpperCase()) 'A' else 'a'
            val shifted = ((char - base + shift) % 26 + base.code).toChar()
            result.append(shifted)
        } else {
            result.append(char) // Keep spaces and punctuation unchanged
        }
    }
    return result.toString()
}

fun decrypt(text: String, shift: Int): String {
    return encrypt(text, 26 - shift) // Reverse the shift
}

fun main() {
    val message = "Hello World"
    val shiftKey = 3
    val encryptedMessage = encrypt(message, shiftKey)
    val decryptedMessage = decrypt(encryptedMessage, shiftKey)
    println("Original: $message")
    println("Encrypted: $encryptedMessage")
    println("Decrypted: $decryptedMessage")
}

How the Kotlin Code Works

encrypt() function

  • Loops over each character.
  • If it’s a letter, shifts it forward by the shift value.
  • Keeps spaces and punctuation as they are.

decrypt() function

  • Reverses the shift to get back the original message.

Example output:

Kotlin
Original: Hello World
Encrypted: Khoor Zruog
Decrypted: Hello World

Real-Life Uses of Cryptography

  • Secure websites: HTTPS uses cryptography to protect data.
  • Digital signatures: Prove a file or message is genuine.
  • Blockchain: Relies on cryptographic hashing for security.

Conclusion

Cryptography is the backbone of digital security.
 It’s what keeps your passwords, bank details, and personal messages safe in a world where cyber threats are everywhere.
 While the math behind it can get deep, the basic idea is simple: scramble information so only the right person can read it.

Vehicle HAL

What Is Vehicle HAL? How Vehicle HAL Is Changing the Way You Drive

In today’s rapidly evolving automotive world, technology increasingly powers every aspect of your driving experience. One such advancement making a significant impact behind the scenes is Vehicle HAL. You might be wondering, what exactly is Vehicle HAL, and how does it affect the way you drive? Let’s break it down clearly and simply.

What Is Vehicle HAL? 

Vehicle HAL stands for Vehicle Hardware Abstraction Layer. Think of it as the translator between the car’s hardware (like sensors, cameras, control units) and the software apps that make your driving experience smarter and safer. It sits in the middle, handling the nitty‑gritty so app developers can focus on features — not on hardware quirks.

With Vehicle HAL, your car’s systems talk in a standard language. Whether it’s braking, lane‑keeping, infotainment, or diagnostics, everything works through that common interface. That consistency simplifies development, improves safety, and speeds up innovation.

Why Vehicle HAL Matters

1. One Interface, Many Devices

Vehicle HAL gives developers a single, reliable interface to access diverse hardware. Instead of building custom code for each sensor or device, they write once and it works across models — much faster and safer.

2. Faster Updates, Smarter Features

Need to add voice commands, predictive cruise control, or advanced diagnostics? Vehicle HAL decouples hardware from apps. That means updates come quicker and you get new features without long delays.

3. Safety First

By enforcing consistent behavior across hardware components, Vehicle HAL helps reduce bugs and improves reliability. Consistency boosts safety — especially in critical systems like braking or collision avoidance.

4. Interoperability & Modularity

Automakers and suppliers can plug in different parts — cameras, sensors, processors — from various vendors. As long as they follow Vehicle HAL standards, everything integrates seamlessly. This encourages competition and innovation while keeping quality high.

How Vehicle HAL Works

Let’s look at a basic example in Android’s Vehicle HAL environment to understand how it controls a vehicle’s power state.

Java
// Example: Controlling Vehicle Power State with Vehicle HAL

public class VehiclePowerController {
    private VehicleHal vehicleHal;

    public VehiclePowerController(VehicleHal hal) {
        this.vehicleHal = hal;
    }

    // Method to turn vehicle power on or off
    public void setPowerState(boolean on) {
        try {
            int powerState = on ? VehiclePropertyIds.POWER_STATE_ON : VehiclePropertyIds.POWER_STATE_OFF;
            vehicleHal.setProperty(VehiclePropertyIds.POWER_STATE, powerState);
            System.out.println("Vehicle power turned " + (on ? "ON" : "OFF"));
        } catch (VehicleHalException e) {
            System.err.println("Failed to set power state: " + e.getMessage());
        }
    }
}

Here,

  • VehicleHal is an object representing the hardware abstraction layer interface.
  • The method setPowerState takes a boolean to turn the vehicle power on or off.
  • VehiclePropertyIds.POWER_STATE_ON and POWER_STATE_OFF are constants representing the hardware power states.
  • The setProperty method sends the command down to the hardware, abstracted away from the specific implementation.

This simple code showcases how Vehicle HAL hides the hardware complexities and presents a clean way to control vehicle functions programmatically.

Benefits of Vehicle HAL for Developers and Drivers

  • For developers: Simplifies app development and testing across multiple vehicle platforms.
  • For drivers: You get a smooth, consistent driving experience with new features delivered faster and more safely.
  • For manufacturers: Promotes modular design, reducing costs and accelerating innovation.

The Future of Driving with Vehicle HAL

As connected and autonomous vehicles advance, the role of Vehicle HAL will grow even more crucial. It will support complex sensor networks, cloud integration, AI-driven decisions, and real-time data sharing between vehicles to make driving smarter, safer, and more enjoyable.

Conclusion

In conclusion, Vehicle HAL is revolutionizing the automotive space by breaking down the barriers between hardware and software. It’s making cars more adaptable, feature-rich, and user-friendly, changing the way you interact with your vehicle every day. Whether it’s through better safety, easier updates, or improved performance, Vehicle HAL is quietly refashioning the future of driving, one line of code at a time.

Drive smarter, safer, and connected — thanks to Vehicle HAL.

ONNX Runtime on Android

ONNX Runtime on Android: The Ultimate Guide to Lightning-Fast AI Inference

Artificial intelligence is no longer limited to servers or the cloud. With ONNX Runtime on Android, you can bring high-performance AI inference directly to mobile devices. Whether you’re building smart camera apps, real-time translation tools, or health monitoring software, ONNX Runtime helps you run models fast and efficiently on Android. In this guide, we’ll break...

Membership Required

You must be a member to access this content.

View Membership Levels

Already a member? Log in here
Android BOM

What Is Android BOM? A Beginner’s Guide to Simplifying Dependencies in 2025

Managing dependencies in Android development can feel like juggling flaming torches—one wrong move, and your build breaks. If you’re tired of mismatched library versions, build errors, and long Gradle files, Android BOM might be the solution you didn’t know you needed.

In this guide, we’ll break down what Android BOM is, why it matters in 2025, and how you can start using it to clean up your project and avoid versioning headaches.

What Is Android BOM?

BOM stands for Bill of Materials. It’s a feature in Gradle (and supported by Maven too) that lets you manage versions of multiple libraries from a single source.

In the Android world, an Android BOM is typically published by a library maintainer (like Google for Jetpack Compose or Firebase) and defines the versioning for all related artifacts under the hood.

Instead of specifying a version number for each dependency manually, you just import the BOM, and it ensures all components stay in sync.

Why Use Android BOM in 2025?

In 2025, modern Android apps rely on a stack of complex, interconnected libraries. Manually managing versions is error-prone and inefficient.

Here’s why Android BOM is a must-have:

Simplifies Dependency Management

No more version conflicts or mismatched components.

Reduces Boilerplate

You can skip version numbers for each Firebase or Jetpack Compose module.

Keeps Everything in Sync

The BOM ensures all included libraries are compatible with each other.

Easier Upgrades

Want to update Firebase? Just bump the BOM version.

How Does It Work?

Here’s what a typical implementation looks like in your build.gradle.kts or build.gradle file:

Without Android BOM (manual versioning):

Kotlin
dependencies {
    implementation("androidx.compose.ui:ui:1.6.1")
    implementation("androidx.compose.material:material:1.6.1")
    implementation("androidx.compose.ui:ui-tooling-preview:1.6.1")
}

Every library needs a version. If you upgrade, you need to change them all manually.

With Android BOM (simplified and synced):

Kotlin
dependencies {
    implementation(platform("androidx.compose:compose-bom:2025.01.00"))
    
    implementation("androidx.compose.ui:ui")
    implementation("androidx.compose.material:material")
    implementation("androidx.compose.ui:ui-tooling-preview")
}

Only the BOM needs a version. The other libraries inherit it automatically. Clean and safe.

Where Can You Use Android BOM?

Android BOM is commonly used with:

  • Jetpack Compose
  • Firebase (via com.google.firebase:firebase-bom)
  • Ktor (JetBrains’ Kotlin server-client library)
  • Any library group that publishes a BOM

It works in both Gradle Kotlin DSL and Groovy.

Each is maintained by the respective teams and updated regularly.

BOM and Version Catalogs

Gradle’s Version Catalogs work perfectly with BOMs. Define the BOM in your libs.versions.toml file:

TOML
[versions]
compose-bom = "2025.05.00"

[libraries]
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
ui = { group = "androidx.compose.ui", name = "ui" }

And in your build.gradle.kts:

Kotlin
implementation (platform(libs.androidx.compose.bom))
implementation (libs.ui)

This keeps your dependency management even more organized.

Best Practices When Using Android BOM

  • Stick to one BOM per group — Don’t mix Firebase and Compose BOMs in a single platform declaration. You can have multiple BOMs, but declare them separately.
  • Keep BOM versions updated — Stay on top of version updates for stability and security.
  • Avoid adding versions to individual artifacts if the BOM already manages them.

What If a Library Doesn’t Support BOM?

Some third-party libraries might not publish a BOM. In that case, you’ll still have to manage versions manually. But you can combine both approaches — use BOM for libraries that support it and pin versions for others.

Overriding BOM Versions

Sometimes, you might need a specific library version that’s newer (or older) than what the BOM provides. You can override it by specifying the version directly:

Kotlin
implementation (platform("androidx.compose:compose-bom:2025.05.00"))
implementation ("androidx.compose.material3:material3:1.2.0-alpha09") // Overrides BOM

Be cautious: overriding can break compatibility guarantees, so only do this if necessary.

Common Questions About Android BOM

Does the BOM automatically add all libraries to my app?

No. You still need to declare each library you want to use. The BOM just manages their versions.

Can I use BOM for alpha or beta releases?

Yes! There are alpha, beta, and stable BOMs available. Just add -alpha or -beta to the BOM artifact name:

Kotlin
implementation (platform("androidx.compose:compose-bom-alpha:2025.05.00"))

Am I forced to use BOM?

No, but it’s highly recommended for easier and safer dependency management.

Does BOM increase build time?

Actually, the opposite. Because it simplifies dependency resolution, it can help Gradle builds run more efficiently.

Conclusion

If you’re building Android apps in 2025, using Android BOM isn’t just a nice-to-have — it’s essential. It streamlines dependency management, prevents version mismatches, and keeps your codebase cleaner and safer.

Whether you’re working on a small app or a complex multi-module project, adopting Android BOM early will save you time and frustration.

What is libs.versions.toml

Mastering libs.versions.toml: Add Plugins, Dependencies & Manage Versions Like a Pro

In modern Android and Kotlin Multiplatform development, managing dependencies across multiple modules can quickly become messy. Manually updating versions in each build.gradle.kts file is not only error-prone—it’s a headache when scaling projects. That’s where libs.versions.toml steps in—the primary and recommended configuration file for Gradle Version Catalogs, a game-changing feature introduced in Gradle 7.0 and stabilized...

Membership Required

You must be a member to access this content.

View Membership Levels

Already a member? Log in here
Migrate from SharedPreferences to Jetpack DataStore

How to Migrate from SharedPreferences to Jetpack DataStore (Step-by-Step Guide)

If you’re still using SharedPreferences in your Android app, it’s time to level up. Google introduced Jetpack DataStore as the modern solution for storing key-value and typed objects in a more efficient, safe, and asynchronous way. In this guide, we’ll walk you through how to migrate from SharedPreferences to Jetpack DataStore, step by step, with...

Membership Required

You must be a member to access this content.

View Membership Levels

Already a member? Log in here
Android Doze Mode

The Truth About Android Doze Mode: Does It Really Save Battery?

If you’ve ever wondered why your Android phone suddenly becomes stingy with background tasks when left idle, the answer likely lies in Doze Mode. Introduced in Android 6.0 (Marshmallow), this feature promised to significantly improve battery life. But does it actually deliver? 

Let’s break it down.

What Is Doze Mode?

Doze Mode is a battery-saving feature that kicks in when your device is idle for an extended period. Think of it as your phone going into “power nap” mode. During Doze, the system restricts background activities such as syncing, GPS, and network access to conserve energy.

Android doesn’t completely shut off these services but defers them to periodic maintenance windows. So your device can still check for important updates — just not every second.

When Does Doze Mode Activate?

Doze Mode isn’t triggered the moment you stop using your phone. Android checks several conditions:

  • The device is unplugged.
  • The screen is off.
  • The phone hasn’t moved for a while.
  • No active wake locks are held by apps.

Once all conditions are met, the phone enters Idle mode, and Doze begins throttling background processes.

Does Doze Mode Really Save Battery?

In one word: Yes — but with context.

Real-World Impact

If you’re someone who leaves their phone idle for long periods (e.g., overnight or during work hours), Doze Mode can significantly extend battery life. Users have reported up to 30% more standby time.

However, if your phone is constantly in use, or you’re moving around with it in your pocket, Doze may not activate often enough to make a noticeable difference.

How Developers Handle Doze Mode

If you’re a developer, ignoring Doze Mode can lead to broken background functionality. Here’s a simple example of how to test if your app works with Doze:

Requesting Exemption from Doze Mode

Java
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    String packageName = context.getPackageName();
    if (!pm.isIgnoringBatteryOptimizations(packageName)) {
        Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
        intent.setData(Uri.parse("package:" + packageName));
        context.startActivity(intent);
    }
}
  • This code checks if your app is excluded from Doze Mode.
  • If it isn’t, it launches a system dialog requesting the user to whitelist your app.
  • Be cautious: this should only be used for essential apps like alarms or health monitors.

Please note, you must have this permission in your AndroidManifest.xml:

<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>

How to Check If Doze Mode Is Hurting App Performance

Some apps rely heavily on real-time background updates (think messaging or location tracking). If users report delays or missed notifications, Doze could be the culprit.

Quick Fix for Users

  1. Go to Settings > Battery > Battery Optimization.
  2. Select “All apps.”
  3. Tap your app and choose “Don’t optimize.”

This removes Doze restrictions for that app, but use sparingly to avoid draining your battery.

How Android Developers Can Handle It

If you’re an app developer, you’ll want to make sure your app behaves properly while Doze Mode is active. Android offers special APIs so your alarms and background jobs don’t get lost in the shuffle.

Example: Scheduling Alarms in Doze Mode

By default, normal alarms are postponed. If your app needs to set a time-sensitive alarm (think: medication reminders or calendar events), you must use setAndAllowWhileIdle():

Java
AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);

alarmMgr.setAndAllowWhileIdle(
    AlarmManager.RTC_WAKEUP,
    triggerAtMillis, // desired trigger time in milliseconds
    alarmIntent
);

How This Works

  • setAndAllowWhileIdle() lets your alarm fire even if Doze Mode is triggered—but only for critical events.
  • Use this carefully, as Android limits how often you can schedule these alarms during Doze to prevent battery drain.

Best Practices for Developers

  1. Use WorkManager: It’s built to handle Doze correctly.
  2. Schedule jobs wisely: Use JobScheduler or AlarmManager with setAndAllowWhileIdle().
  3. Test aggressively: Use adb shell dumpsys deviceidle to simulate Doze in development.

Final Verdict: Is Doze Mode Worth It?

Absolutely. For most users, Doze Mode runs silently in the background, extending battery life without sacrificing usability. It’s one of those features that just works — when you let it.

However, for power users and developers, understanding how Doze interacts with apps is essential. Used properly, Doze Mode strikes a smart balance between saving power and staying connected.

So yes, Doze Mode really does save battery. It’s not a gimmick — just smart engineering.

TL;DR (Too Long; Didn’t Read)

  • Doze Mode saves battery by pausing background tasks when your phone is idle.
  • It’s most effective when the device is stationary and unused.
  • Developers must adapt their apps to work within Doze constraints.
  • It works quietly, efficiently, and yes — it makes a real difference.

Frequently Asked Questions

Will I Miss Important Calls or Messages Because of Doze Mode?

No, Doze Mode is designed to allow high-priority push notifications and alarm clock events even while active, so you don’t miss critical alerts.

Can I Turn Off Doze Mode?

By default, Doze Mode is automatic and always-on from Android 6.0 onward. You can exclude specific apps via Android settings if you need certain apps to bypass it, but this can hurt your battery life.

Does Doze Mode Replace Battery Saver?

No, it’s a different feature. Battery Saver is a manual or automatic mode you can toggle, restricting performance and features for more aggressive savings. Doze Mode works behind the scenes automatically, focusing on background tasks while idle

error: Content is protected !!