我正在使用 Kotlin 和 compose 制作一个 Android 应用程序,并使用 GSON 来解析从 API 检索的一些 JSON。然后将数据放入列表中并从函数返回。我有一个可组合项,应该为列表中的每个项目绘制,但返回列表的函数位于协程上。这是我尝试绘制它们的方法,但应用程序崩溃了。
val mutableBricksList = remember { mutableStateOf(listOf<LegoPart>()) }
Button(onClick = {
GlobalScope.launch(Dispatchers.IO) {
val fetchedLegoBricks =
fetchLegoSetBricks("https://rebrickable.com/api/v3/lego/sets/${setNumber}/parts/?key=${BuildConfig.API_KEY}")
if (fetchedLegoBricks != null) {
withContext(Dispatchers.Main) {
mutableBricksList.value = fetchedLegoBricks
}
}
}
}) {
Text("Load Bricks")
}
mutableBricksList.value.forEach { legoPart ->
Brick(
brickNumber = legoPart.part.partNum,
brickName = legoPart.part.name,
imageURL = legoPart.part.partImgUrl
)
println(legoPart.part.name)
}
如果你想要它,这里是返回列表的函数
suspend fun fetchLegoSetBricks(url: String): List<LegoPart>? = withContext(Dispatchers.IO) {
val client = OkHttpClient()
val request = Request.Builder()
.url(url)
.build()
try {
val response = client.newCall(request).execute()
val responseBody = response.body?.string()
// Parse JSON using Gson library
val gson = Gson()
val legoResponse = gson.fromJson(responseBody, LegoResponse::class.java)
val legoPartsList = legoResponse.results
legoPartsList
} catch (e: Exception) {
println("Error fetching LEGO parts: $e")
null
}
}
如果您想查看所有代码,该项目位于公共 GitHub 存储库中:https://github.com/IAMGeeCee/BrickBox。
我尝试过使用 LaunchedEffect 并让它不在按下按钮时以及在绘制可组合项时使用,但这也不起作用。
您可以发布应用程序崩溃时 logcat 中显示的堆栈跟踪吗?将有助于调试原因。
除此之外,我还发现了一些不正确的用法/可以进行的改进:
将
val mutableBricksList = remember { mutableStateOf(listOf<LegoPart>()) }
替换为 val mutableBricksList = remember { mutableStateListOf<LegoPart>() }
。然后,您可以通过执行 mutableBricksList.add(...) 来简单地添加到 mutableBricksList
不正确使用
Globalscope
。理想情况下,人们不应该花时间在点击监听器中进行操作。相反,只需在视图模型中执行操作并调用视图模型的函数即可。然后,您可以优雅地处理挂起函数,在视图模型内执行耗时操作。
LaunchedEffect(key1=Unit){...}
应该可以。您能在这里解释一下什么不起作用吗?示例代码将不胜感激。 (无法查看回购协议,抱歉)
在函数
fetchLegoSetBricks(..)
中,理想情况下,不要在每次单击完成时都创建网络客户端。这是资源密集型的。只需在视图模型中创建一次,最好将其作为视图模型的依赖项注入。最佳实践也不是公开网络客户端,而是公开处理任务的用例或存储库(在本例中从 API 获取并解析它)。
将
MutableStateFlow(..)
暴露给充当状态持有者的父可组合项,即定义一个数据类,该数据类将保存 API 响应以及 isLoading: Boolean 等其他属性。然后使用推荐的 <your-state-flow>.collectAsStateWithLifecycle()
监听此状态流。每当您更新状态流(也称为数据类的属性)时,它都会触发重组,并且您的父可组合项将重新渲染。
希望这对您有帮助。祝您安卓之旅愉快! :)