https://kotlinlang.org logo
#android
Title
# android
s

Sven Obser

06/23/2022, 3:09 PM
Hi everyone, I just realized that
kotlin.random.Random
produces the same “random” values with each app start on Android. 😨 Is this expected behavior?
Copy code
Log.e { "java.util.Random().nextInt(): ${java.util.Random().nextInt()}" }
Log.e { "kotlin.random.Random.nextInt(): ${kotlin.random.Random.nextInt()}" }
Output:
Copy code
java.util.Random().nextInt(): -1853486751
kotlin.random.Random.nextInt(): -351317653

java.util.Random().nextInt(): 1794921748
kotlin.random.Random.nextInt(): -351317653

java.util.Random().nextInt(): 1849140367
kotlin.random.Random.nextInt(): -351317653
e

ephemient

06/23/2022, 3:17 PM
it's a bug in Android. Kotlin uses java.util.concurrent.ThreadLocalRandom, which Android initializes in zygote. then each app forks off zygote with the same state.
s

Sven Obser

06/23/2022, 3:30 PM
This sounds really bad. So the only workaround would be to use a custom
val random = java.util.Random().asKotlinRandom()
and supply it to the caller (e.g.
listOf().shuffle(random)
)!?
k

kevindmoore

06/23/2022, 3:33 PM
I always thought that Random functions always do that. I thought you had to provide a "seed" to get a truly random number (Not sure about Kotlin's version)
e

ephemient

06/23/2022, 3:34 PM
ThreadLocalRandom.current()
is supposed to be pre-seeded. the issue is that it was pre-seeded upon initialization in zygote, and every app gets a clone of the same instance
s

Sven Obser

06/23/2022, 3:36 PM
@kevindmoore It should be the other way round. If you provide the same seed, you get the same numbers. But at least the
java.util.Random()
gives a a Random with a Random seed.
e

ephemient

06/23/2022, 4:22 PM
as a short-term workaround, I think if you prevent Kotlin from using Java 8 then it'll fall back to a locally-seeded
ThreadLocal<java.util.Random>
to implement
kotlin.random.Random.Default
, e.g. with
Copy code
dependencies {
    modules {
        module(kotlin("stdlib-jdk8")) {
            replacedBy(kotlin("stdlib-jdk7"), "<https://issuetracker.google.com/issues/234631055>")
        }
    }
}
in your
build.gradle.kts
. but that's a pretty terrible hack that could break other dependencies (as it also means dropping regex capture groups and java stream/time extensions) and won't work long-term (Kotlin is phasing out pre-Java 8 support, https://youtrack.jetbrains.com/issue/KT-45165)
s

Sven Obser

06/24/2022, 7:52 AM
Thanks a lot for all those links. Glad that this issue seems to get some attention!
69 Views