Random Number Generation in Android on Kotlin: What's Under the Hood?

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

How to Make Android "Roll the Dice"? Breaking Down Random Number Generation in Kotlin

\n\n

Have you ever wondered how your phone "chooses" a random number? It seems like a simple task — get a random integer from 5 to 10. But under the hood of Android and Kotlin lies a whole mechanism that affects not only convenience but also the security of your application. It's no surprise that the question "How can I generate random number in specific range in Android?" has gathered thousands of views on Stack Overflow. We won't just give a ready-made answer — we'll look into the source code and figure out what's really happening.

\n\n

In this article, you will learn:

\n
    \n
  • How to correctly generate a random number in a given range in Kotlin.
  • \n
  • How kotlin.random.Random, java.util.Random, and SecureRandom differ.
  • \n
  • Why one class is needed for games of chance and another for password generation.
  • \n
  • How to avoid common mistakes that turn "randomness" into predictability.
  • \n
\n\n

Let's go!

\n\n

The Classic: Random in Kotlin (and Why It's Not Always Right)

\n\n

The most obvious way is to use kotlin.random.Random. It's built right into the language and works out of the box. Here's how generating a random number from 0 to 100 (inclusive) looks:

\n\n
import kotlin.random.Random\n\nfun main() {\n    val randomNumber = Random.nextInt(0, 101) // from 0 to 100 inclusive\n    println("Random number: $randomNumber")\n}
\n\n

It's simple. But let's look under the hood. Random.nextInt(from, until) internally uses java.util.Random (on the JVM platform). That, in turn, generates numbers using a linear congruential generator (LCG). The formula is simple:

\n\n

new_seed = (old_seed * A + C) mod M

\n\n

Where A, C, and M are constants. It's fast, but not cryptographically secure. If an attacker learns even a few numbers, they can recover the seed and predict all subsequent ones.

\n\n

When to use: For games (not for money), randomly selecting an item from a list, shuffling cards in a regular application.

\n\n

Advanced Level: ThreadLocalRandom for Multithreading

\n\n

If your application actively uses coroutines or multithreading, a regular Random can become a bottleneck. Each call to nextInt() is synchronized to avoid race conditions. The solution is ThreadLocalRandom from Java:

\n\n
import java.util.concurrent.ThreadLocalRandom\n\nfun getRandomInRange(min: Int, max: Int): Int {\n    return ThreadLocalRandom.current().nextInt(min, max + 1)\n}
\n\n

This class allocates a separate instance of Random for each thread. No synchronization is needed — each thread works with its own generator. In practice, this gives a performance boost in multithreaded scenarios.

\n\n

Security Above All: SecureRandom

\n\n

Now imagine you are generating a one-time password (OTP) or a token for account recovery. Using a regular Random is a crime. This is where SecureRandom comes in:

\n\n
import java.security.SecureRandom\n\nfun generateSecureCode(length: Int): String {\n    val secureRandom = SecureRandom()\n    val digits = "0123456789"\n    return (1..length)\n        .map { digits[secureRandom.nextInt(digits.length)] }\n        .joinToString("")\n}
\n\n

SecureRandom collects entropy from operating system sources: microphone noise, keyboard timing (in the emulator — from the file /dev/random or /dev/urandom). This makes it unpredictable. But this comes at the cost of speed — it can be tens of times slower than a regular Random.

\n\n

Important: On Android, S

Blogs

Book Recommendations