我正在使用JSON资产文件将一些数据作为列表加载到应用程序中。
fun onGeneral(context: Context): List<List<General>> {
try {
val json = context.assets.open("general.json").bufferedReader().use { it.readText() }
val list = Gson().fromJson<List<General>>(json, object : TypeToken<List<General>>() {}.type)
return listOf(
list.subList(0, 30),
list.subList(30, 60),
list.subList(60, 90),
list.subList(90, 120),
list.subList(120, 150),
list.subList(150, 180),
list.subList(180, 210),
list.subList(210, 240),
list.subList(240, 270),
list.subList(270, 300)
)
} catch (e: Exception) {
return emptyList()
}
}
由于列表很大,我将其划分为子列表,结果,我在屏幕中得到了一个子列表列表:
var items = remember { mutableStateListOf<Item>() }
val context = LocalContext.current
val general = onGeneral(context)[0] // The first entry
然后,我将一般列表添加到项目中:
general.forEach { items.add(Item(it)) }
在屏幕的某个地方我显示了计数器
Text("Item ${position + 1} of ${items.size}")
问题是当进入屏幕时,文本应显示
Item 1 of 30
但它显示了一个不停的计数器
它一直在计数。
此外,我添加了一个日志,看看有什么正在发生:
Log.wtf("TST_Output", "Say Hello, when screen entered!")
输出:
....
E/TST_Output: Say Hello, when screen entered!
E/TST_Output: Say Hello, when screen entered!
E/TST_Output: Say Hello, when screen entered!
E/TST_Output: Say Hello, when screen entered!
E/TST_Output: Say Hello, when screen entered!
E/TST_Output: Say Hello, when screen entered!
E/TST_Output: Say Hello, when screen entered!
E/TST_Output: Say Hello, when screen entered!
E/TST_Output: Say Hello, when screen entered!
E/TST_Output: Say Hello, when screen entered!
E/TST_Output: Say Hello, when screen entered!
E/TST_Output: Say Hello, when screen entered!
E/TST_Output: Say Hello, when screen entered!
E/TST_Output: Say Hello, when screen entered!
E/TST_Output: Say Hello, when screen entered!
E/TST_Output: Say Hello, when screen entered!
....
它无止境...
我理解,日志输出是由此行引起的
general.forEach { items.add(Item(it)) }
但是,当forEarch
循环完成后,不应该再重复一次,为什么它一直在运行?
我尝试了一下,找到了一个不用重复的解决方案:
var items: MutableList<Item> = remember { mutableStateListOf() }
val temp = arrayListOf<Item>()
general.forEach { temp.add(Item(it)) }
items = temp
将items
变量指定为MutableList<Item>
似乎可以工作。
另外,不管上面的问题,我将日志行添加到另一个屏幕,在那里我不检索任何数据。在这种情况下,日志行应该触发一次,但这里的日志:
......
D/ViewRootImpl@e8d5d7b[MainActivity]: reportDrawFinished (fn: -1)
E/TST_Output: Say Hello, when screen entered! <!!!!!!!!!!----------!!!!!!!!
D/CompatibilityChangeReporter: Compat change id reported: 171228096; UID 11701; state: ENABLED
I/ViewRootImpl@e8d5d7b[MainActivity]: Relayout returned: old=(0,0,1440,3040) new=(0,0,1440,3040) req=(1440,3040)0 dur=6 res=0x1 s={true 500687993696} ch=false fn=2
I/OpenGLRenderer: Davey! duration=793ms; Flags=0, FrameTimelineVsyncId=8404895, IntendedVsync=215478232101981, Vsync=215478448768639, InputEventId=0, HandleInputStart=215478449436685, AnimationStart=215478449438954, PerformTraversalsStart=215478749464762, DrawStart=215478991676915, FrameDeadline=215478265435313, FrameInterval=215478449418954, FrameStartTime=16666666, SyncQueued=215479007135992, SyncStart=215479007221531, IssueDrawCommandsStart=215479007348107, SwapBuffers=215479020229915, FrameCompleted=215479025430838, DequeueBufferDuration=20731, QueueBufferDuration=1477346, GpuCompleted=215479025430838, SwapBuffersCompleted=215479022577992, DisplayPresentTime=1554322967633985549,
E/TST_Output: Say Hello, when screen entered! <!!!!!!!!!!----------!!!!!!!!
I/ViewRootImpl@e8d5d7b[MainActivity]: MSG_WINDOW_FOCUS_CHANGED 1 1
D/InputMethodManager: startInputInner - Id : 0
I/InputMethodManager: startInputInner - mService.startInputOrWindowGainedFocus
D/InputMethodManager: startInputInner - Id : 0
W/System: A resource failed to call close.
E/TST_Output: Say Hello, when screen entered! <!!!!!!!!!!----------!!!!!!!!
......
如您所见,该行(标记为<!!!!!!!!!!----------!!!!!!!!
)被触发了三次。
wong是什么?为什么喷气背包组合的行为如此奇怪?我做错了什么吗?
任何帮助都会很有帮助。非常感谢。
编辑:
屏幕代码:
@Composable
@Preview(showBackground = true)
@OptIn(ExperimentalPagerApi::class)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
fun GeneralScreen(controller: NavController = rememberNavController()) {
val context = LocalContext.current
var items: MutableList<Item> = remember { mutableStateListOf() }
var list by remember { mutableStateOf(1) }
var position by remember { mutableStateOf(0) }
val general = onGeneral(context)[0]
val temp = arrayListOf<Item>()
general.forEach {
temp.add(Item(it))
}
items = temp
Log.wtf("TST_Output", "Say Hello, when screen entered!")
Column(Modifier.fillMaxWidth().padding(10.dp), Arrangement.spacedBy(8.dp), Alignment.CenterHorizontally) {
Text("General list $list", fontSize = 18.sp)
Text("Item ${position + 1} of ${items.size}", fontSize = 16.sp, color = Color.Gray)
}
}
1条答案
按热度按时间uemypmqf1#
项目列表增长的原因是因为您在可组合范围内向列表添加项目。因此,每次屏幕重新组合时,您的项目都将重新添加到列表中。这同样适用于您之前添加的日志条目。这也将记录每次屏幕重新组合时的情况。
您可以通过将逻辑封装在LaunchedEffect块中来防止这种情况。此块仅在其键更改时才在重新组合后运行。以下是一个示例:
由于我们传递Unit作为键给LaunchedEffect,这将只运行一次,因为Unit不会改变。如果你想在每次general改变时运行LaunchedEffect内的代码,你可以使用general作为键,如下所示:
我希望这是有帮助的,如果你想了解更多关于副作用,你可以阅读this。