在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
相关产品推荐
相关产品推荐

