You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Jetpack Compose中实现Kotlin随机数仅生成一次的问题

解决Composable中随机数重复生成的问题

问题现状

你需要给从数组中取出的Int值(比如45)仅添加一次15-45之间的随机数,但当前代码在Composable重组时会频繁生成新的随机数,导致time1s频繁变动,日志显示同一分支下随机数会被生成数十到数百次。

问题原因

Composable函数会在状态变化时自动重组,每次重组都会重新执行函数内的代码。你当前在if分支里直接调用timeList.random(),导致每次重组都会生成新的随机数,而不是仅生成一次。

解决方案

方案1:用remember缓存随机数(推荐)

利用Jetpack Compose的remember函数,将随机数缓存起来,仅当关联的状态(比如songVar)变化时才重新生成:

@Composable
fun name(
    // 其他变量
    songVar: String,
    arrayOfSongs: List<List<String>>
) {
    val timeList = listOf(
        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
        26, 27, 28, 29, 30, 31, 32, 33, 34, 25, 36,
        37, 38, 39, 40, 41, 42, 42, 44, 45
    )

    if (songVar != "") {
        val index = arrayOfSongs.indexOfFirst { it[0] == songVar }
        time1m = (arrayOfSongs[index][1]).toInt()
        val baseSeconds = (arrayOfSongs[index][2]).toInt()
        // 仅当songVar变化时,才重新生成随机偏移量
        val randomOffset = remember(songVar) { timeList.random() }
        time1s = baseSeconds + randomOffset
        Log.d("random1", time1s.toString())
    } else {
        time1m = 0
        time1s = 0
    }
}

remember(songVar)的作用是:将随机偏移量与songVar绑定,只有当songVar改变时,才会重新计算随机数;同一个songVar对应的随机数会被缓存,重组时复用。

方案2:提前在ViewModel生成并缓存随机数

如果需要在整个应用生命周期内保持每个歌曲的随机数不变,可以在ViewModel中预生成并缓存:

class SongViewModel : ViewModel() {
    private val timeList = listOf(
        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
        26, 27, 28, 29, 30, 31, 32, 33, 34, 25, 36,
        37, 38, 39, 40, 41, 42, 42, 44, 45
    )
    // 用Map缓存每个歌曲对应的随机偏移量
    private val songRandomOffsets = mutableMapOf<String, Int>()

    fun getRandomOffset(songId: String): Int {
        // 如果该歌曲还没有随机数,生成并缓存;否则直接返回缓存值
        return songRandomOffsets.getOrPut(songId) {
            timeList.random()
        }
    }
}

然后在Composable中调用:

@Composable
fun name(
    // 其他变量
    songVar: String,
    arrayOfSongs: List<List<String>>,
    viewModel: SongViewModel = viewModel()
) {
    if (songVar != "") {
        val index = arrayOfSongs.indexOfFirst { it[0] == songVar }
        time1m = (arrayOfSongs[index][1]).toInt()
        val baseSeconds = (arrayOfSongs[index][2]).toInt()
        // 从ViewModel获取缓存的随机数
        val randomOffset = viewModel.getRandomOffset(songVar)
        time1s = baseSeconds + randomOffset
        Log.d("random1", time1s.toString())
    } else {
        time1m = 0
        time1s = 0
    }
}

这种方式下,每个歌曲的随机数在第一次获取时生成,之后无论Composable如何重组,都会复用缓存的值。

内容的提问来源于stack exchange,提问作者The Quackiest

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 18:06:29