Como fazer o Android "lançar dados"? Analisando a geração de números aleatórios em Kotlin
\n\nVocê já se perguntou como seu telefone "escolhe" um número aleatório? Parece uma tarefa simples — obter um inteiro aleatório de 5 a 10. Mas por baixo dos panos do Android e Kotlin, esconde-se todo um mecanismo do qual depende não apenas a conveniência, mas também a segurança do seu aplicativo. Não é surpresa que a pergunta "How can I generate random number in specific range in Android?" tenha milhares de visualizações no Stack Overflow. Não vamos apenas dar uma resposta pronta — vamos mergulhar nos fontes e entender o que realmente acontece.
\n\nNeste artigo, você aprenderá:
\n- \n
- Como gerar corretamente um número aleatório em um intervalo específico em Kotlin. \n
- Quais as diferenças entre
kotlin.random.Random,java.util.RandomeSecureRandom. \n - Por que para jogos de azar é necessária uma classe, e para geração de senhas, outra. \n
- Como evitar erros típicos que transformam "aleatoriedade" em previsibilidade. \n
Vamos nessa!
\n\nClássico do gênero: Random em Kotlin (e por que nem sempre é o correto)
\n\nA maneira mais óbvia é usar kotlin.random.Random. Ele está embutido diretamente na linguagem e funciona de fábrica. Veja como é a geração de um número aleatório de 0 a 100 (inclusive):
import kotlin.random.Random\n\nfun main() {\n val randomNumber = Random.nextInt(0, 101) // de 0 a 100 inclusive\n println("Número aleatório: $randomNumber")\n}\n\nTudo simples. Mas vamos olhar por baixo dos panos. Random.nextInt(from, until) internamente usa java.util.Random (na plataforma JVM). E este, por sua vez, gera números usando um gerador linear congruencial (LCG). A fórmula é simples:
new_seed = (old_seed * A + C) mod M
Onde A, C e M são constantes. Isso é rápido, mas não é criptograficamente seguro. Se um invasor descobrir alguns números, ele pode recuperar a seed e prever todos os subsequentes.
\n\nQuando usar: Para jogos (que não envolvam dinheiro), seleção aleatória de um elemento de uma lista, embaralhamento de cartas em um aplicativo comum.
\n\nNível avançado: ThreadLocalRandom para multithreading
\n\nSe seu aplicativo usa ativamente coroutines ou multithreading, o Random comum pode se tornar um gargalo. Cada chamada a nextInt() é sincronizada para evitar condições de corrida. A solução é ThreadLocalRandom do Java:
import java.util.concurrent.ThreadLocalRandom\n\nfun getRandomInRange(min: Int, max: Int): Int {\n return ThreadLocalRandom.current().nextInt(min, max + 1)\n}\n\nEsta classe aloca uma instância separada de Random para cada thread. A sincronização não é necessária — cada thread trabalha com seu próprio gerador. Na prática, isso proporciona um ganho de desempenho em cenários multithread.
Segurança acima de tudo: SecureRandom
\n\nAgora imagine que você está gerando uma senha de uso único (OTP) ou um token para recuperação de acesso. Usar o Random comum é um crime. É aqui que entra o SecureRandom:
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\nO SecureRandom coleta entropia de fontes do sistema operacional: ruídos do microfone, temporizações de pressionamento de teclas (no emulador, do arquivo /dev/random ou /dev/urandom). Isso o torna imprevisível. Mas isso tem um custo em velocidade — ele pode ser dezenas de vezes mais lento que o Random comum.
Importante: No Android, o S