我是编写和声明性编程的新手,我正在努力理解它.为了学习,在阅读了教程和观看了课程后,现在我正在创建我的第一个应用程序.

我正在创建一个具有Compose多平台的合成桌面应用程序,它将允许您从计算机中 Select 一个文件夹并显示该文件夹中的所有文件.我要用JFileChooser来 Select 一个文件夹.当它被选中时,状态变量被更改,并且Box被填充表示该文件夹中的文件名的文本.这些名称由使用JFileChooser返回的路径的函数获得.

这款应用程序有两个奇怪的行为.首先,因为屏幕上有一个TextField,如果我在里面写,填满文本的Box似乎会被重新绘制,再次调用搜索文件的函数(这些文件可能是数千个,这会减缓应用程序的运行速度).

第二个奇怪的行为是,如果我再次打开JFileChooser来更改文件夹,它会正确地重新绘制Box,并获得该文件夹的文件名,但如果我 Select 先前 Select 的相同文件夹,Box不会重新绘制,如果该文件夹中的文件发生更改,就会出现问题.

有没有人能帮我理解一下Compose的这些问题?我认为这两个问题都与声明性写作逻辑有关,但不能理解哪里错了.谢谢.

这是显示JFileChooser的按钮

var listRomsState by remember { mutableStateOf(false) }
Button(onClick = {
    folderChosenPath = folderChooser()
    if (folderChosenPath != "")
        listRomsState = true
}) {
    Text(text = "List roms")
}

这是显示JFileChooser的函数

fun folderChooser(): String {
    UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
    val f = JFileChooser()
    f.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY

    val result: Int = f.showSaveDialog(null)
    if (result == JFileChooser.APPROVE_OPTION) {
        return f.selectedFile.path
    } else {
        return ""
    }
}

在显示文件 Select 器的按钮下方是包含文件名的列表:

if (listRomsState) {
    RomsList(File(folderChosenPath))
}

这是RomsList函数:

@Composable
fun RomsList(folder: File) {
    Box (
        modifier = Modifier.fillMaxSize().border(1.dp, Color.LightGray)
    ) {
        LazyColumn(
            Modifier.fillMaxSize().padding(top = 5.dp, end = 8.dp)
        ){
            var romsList = getRomsFromFolder(folder)
            items(romsList.size) {
                Box (
                    modifier = Modifier.padding(5.dp, 0.dp, 5.dp, 0.dp).fillMaxWidth(),
                    contentAlignment = Alignment.CenterStart
                ) {
                    Row (horizontalArrangement = Arrangement.spacedBy(5.dp)){
                        Text(text = "" + (it+1), modifier = Modifier.weight(0.6f).background(color = Color(0, 0, 0, 20)))
                        Text(text = romsList[it].title, modifier = Modifier.weight(9.4f).background(color = Color(0, 0, 0, 20)))
                    }
                }
                Spacer(modifier = Modifier.height(5.dp))
            }
        }
    }
}

以下是递归获取文件夹的所有文件名的函数:

fun getRomsFromFolder(curDir: File? = File(".")): MutableList<Rom> {
    var romsList = mutableListOf<Rom>()

    val filesList = curDir?.listFiles()
    filesList?.let {
        for (f in filesList) {
            if (f.isDirectory) romsList.addAll(getRomsFromFolder(f))
            if (f.isFile) {
                romsList.add(Rom(f.name))
            }
        }
    }

    return romsList
}

推荐答案

最后,在Steyrix、Z.y和其他一些人的帮助下,我发现了一些东西.

首先,正如这里所指出的,https://developer.android.com/jetpack/compose/mental-model#recomposition个可组合函数只有在它们的参数被更改时才执行它们的代码,这就是问题2的原因.

另外,这两个问题的主要问题是,我执行的逻辑是在错误的位置检索文件夹中的所有文件.它是在一个可组合的函数中执行的,这是一个问题,因为每次重组它都会被执行.因此,在收到文件 Select 器的结果之后,将逻辑移到onClick就解决了这两个问题.

此外,现在我了解了更多的事情.

谢谢你们!

Android相关问答推荐

Kotlin多平台向导,不兼容版本(ANP 8.2.0)ANP 8.1.2

将Any强制转换为Integer将从API返回NullPointerException

Android开发:主题排版不适用于按钮文本

这款应用与最新版本的Android不兼容.在Android 14中

房间@嵌入式VS一对一关系

Android可绘制边框删除底线

Android Jetpack Compose调用view-model函数仅一次

AndroidX Media3 迁移指南

在 Bash 脚本中使用 XMLLINT 解析 XML 单元测试文件,并将其放入数组中以表示成功和失败

如何在 Jetpack Compose 中处理水平滚动手势和变换手势

Jetpack Compose:在屏幕外制作长水平图像的动画

我的自定义小吃店不适合我的全宽屏幕尺寸

未解决的参考:pagerTabIndicatorOffset

PayUCheckoutPro Android SDK 实现问题

Jetpack Compose Material3 禁用 ListItem

Android Studio 错误要求依赖它的库和应用程序针对 Android API 的 33 版或更高版本进行编译.

在jetpack compose中将图像添加到脚手架顶部栏

基线配置文件 x R8/Proguard

在 Android 10 (API 29) 中隐藏状态栏并在应用程序中使用其空间

Android Java Keystore 在另一台机器上损坏