提问者:小点点

如何设置文本视图的片段与静态编程语言?


在我的项目中使用Android Studio中的“BottomN航空”模板,我面临着如何更新片段的文本视图的问题。

AndroidStudio中的“BottomN航空”模板有一个HomeFragment. kt,我可以从以下位置设置文本视图:

覆盖乐趣onViewCreated(视图:视图,保存InstanceState:捆绑包?){…}

但是,如果我这样启动CoroutineScope():

CoroutineScope(Dispatchers.IO).launch {
    test_function()
}

我无法从test_function()中更新文本视图。

这里特别失败:

private suspend fun client(address : String, port: Int) {
    val connection: Socket

    try {
        connection = Socket(address, port)
    }
    catch(e: Exception) {
        textView.text = "Error: Socket exception: " + e
        return
    }
    val writer = connection.getOutputStream()
    writer.write(1)
    val reader = Scanner(connection.getInputStream())
    textView.text = "test string"
    ...
}

它在以下行失败:

textView.text = "test string"

通过崩溃。

我应该从test_function()中使用findViewById()来获取我的文本视图的句柄(?)或其他东西吗?即使这是正确的解决方案,我也会遇到以下错误:

Unresolved reference: findViewById

我需要做什么才能从CoroutineScope调用的函数中更新text View?


共1个答案

匿名用户

您没有共享堆栈跟踪,但我假设问题是您从主线程以外的线程更新TextView,这是不允许的。

按照惯例,挂起函数应该总是在内部将工作委托给适当的调度程序。因此,如果上面的代码中有任何阻塞函数调用,您应该将它们包装在with Context(Dispatchers.IO) { }中,同样,您应该将修改视图的代码部分包装在with Context(Dispatcher. Main) { }中。例如:

private suspend fun client(address : String, port: Int) = withContext(Dispatchers.IO) {
    val connection: Socket

    try {
        connection = Socket(address, port)
    }
    catch(e: Exception) {
        withContext(Dispatchers.Main) { textView.text = "Error: Socket exception: " + e }
        return
    }
    val writer = connection.getOutputStream()
    writer.write(1)
    val reader = Scanner(connection.getInputStream())
    withContext(Dispatchers.Main) {  textView.text = "test string" }
    ...
}

当您启动协程时,如果它只是调用挂起函数和非阻塞函数,则无需在那里指定调度程序,假设您已适当遵循上述约定。

此外,您很少需要像在代码中那样创建自己的协程范围。在这种情况下,如果由于配置更改或应用程序挂起并恢复后重新创建了您的Fragment,您的协程可能仍在运行,这会泄漏内存,并且如果您尝试访问Context,可能会导致崩溃。您应该使用viewLiftycleOwner. liftycleScope在Fragment中启动您的协程。当片段视图被销毁时,它会自动停止。