如何在协程中制作吐司消息?

How to make a toast message in a coroutine?

设置

假设我有一个创建 toast 消息的函数

fun makeToast(success: Boolean){
    if (success){
        Toast.makeText(someContext, "Success", Toast.LENGHT_SHORT).show()
    }
}

此函数用于另一个被挂起的函数,例如

suspend fun makeRequest(){
    success = doSomeHTTPRequest()
    makeToast(success)
}

当我使用此函数执行请求时,我将在 IO 协程中执行,例如

CoroutineScope(IO).launch{
    makeRequest()
}

问题

按照上面的建议进行操作会导致:

java.lang.NullPointerException: Can't toast on a thread that has not called Looper.prepare()

问题

解决此问题的最佳做法是什么?直接的方法是将 makeToast 更改为

fun makeToast(success: Boolean){
    if (success){
        Looper.prepare()
        Toast.makeText(someContext, "Success", Toast.LENGHT_SHORT).show()
        Looper.loop()
    }
}

然而这感觉很尴尬,因为这意味着函数 makeToast 已经知道它可能不会在主线程中被调用,这在我看来会产生奇怪的耦合。

当 运行 代码只允许从主线程调用时,您需要指定使用 Main 调度程序。我想从错误消息中它建议你可以使用其他线程,如果他们有一个准备好的 Looper,但是如果你只是从主线程中专门制作 Toasts 会容易得多。

此外,一个正确组合的挂起函数应该可以安全地从 任何 调度程序调用。您永远不必指定 Dispatcher 来调用挂起函数。当您调用阻塞代码并因此需要指定适当的后台调度程序时,或者在调用需要在主线程上调用的函数时,应指定调度程序。

因此,您可以从 launch 通话中删除 (IO)。在你的 makeRequest 函数中,在调用阻塞函数或 main-exclusive 函数的地方指定你的调度程序:

suspend fun makeRequest(){
    val success = withContext(Dispatchers.IO) { 
        doSomeHTTPRequest()
    }
    withContext(Dispatchers.Main) {
        makeToast(success)
    }
}

在应用程序中显示 Toast 消息的最佳方式 Step 1 创建kotlin class ToastMessage.kt 并编写代码


import android.content.Context
import android.widget.Toast

fun Context.tost(message: String) = Toast.makeText(this, message, Toast.LENGTH_SHORT).show()

/*call this method to any class*/

this.tost("successfuly show message")