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

如何在后台线程访问URL解析XML取值并在Jetpack Compose UI展示

问题原因
  • 你遇到的NetworkOnMainThreadException是因为安卓系统禁止在主线程执行网络操作,你虽然用了lifecycleScope.launch,但协程默认调度到主线程运行,网络逻辑还是跑在主线程才触发了异常。
  • 给test加suspend修饰符提示冗余,是因为你函数内部没有调用任何挂起函数,也没有指定线程调度器,suspend关键字没有实际作用。
修正方案

第一步:修改test函数

给test加上suspend修饰,内部用withContext(Dispatchers.IO)把网络和解析逻辑切到后台线程:

suspend fun test(): List<String> = withContext(Dispatchers.IO) {
    val names = mutableListOf<String>()
    val user = "User"
    val url = URL("https://www.boardgamegeek.com/xmlapi/collection/$user?own=1")
    val http: HttpURLConnection = url.openConnection() as HttpURLConnection
    http.doInput = true
    http.connect()
    Log.d("bgg", "first" )
    var games: List<Game>? = null
    try {
        val parser = XmlPullParserHandler()
        val istream = http.inputStream
        games = parser.parse(istream)
    } catch (e: IOException) {
        e.printStackTrace()
    } finally {
        // 用完关闭连接避免资源泄漏
        http.disconnect()
    }
    games?.forEach { 
        it.name?.let { name -> names.add(name) }
        Log.d("bgg", "game" + it.name)
    }
    Log.d("bgg", "second" + names.toString())
    names
}

第二步:修改Compose逻辑,用状态持有异步返回的结果

不要在setContent里直接调用test,而是用Compose的状态容器存列表,用LaunchedEffect触发异步请求:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
        MyApp {
            // 用state存游戏名称列表,初始为空列表
            val gameNamesState = remember { mutableStateOf(emptyList<String>()) }
            // 进入页面时自动发起请求
            LaunchedEffect(Unit) {
                gameNamesState.value = test()
            }
            // 把state里的列表传给UI组件,数据更新时自动刷新UI
            MyScreenContent(gameNamesState.value)
        }
    }
}

第三步:添加网络权限

在项目的AndroidManifest.xml根标签下添加网络访问权限,否则会请求失败:

<uses-permission android:name="android.permission.INTERNET" />
关键逻辑说明
  • withContext(Dispatchers.IO):会把包裹的代码块调度到IO专用的后台线程池执行,不会阻塞主线程,也不会触发主线程网络的异常。
  • LaunchedEffect:是Compose内置的协程启动API,只会在组合进入时执行一次里面的逻辑,请求完成后更新state的值,Compose会自动检测到状态变化,触发UI重组刷新列表展示。
  • 如果你需要点击按钮刷新数据,可以在按钮的点击回调里用rememberCoroutineScope启动协程调用test函数更新state即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 13:00:01