Kotlin 使用协程时出现NetworkOnMainThreadException

Kotlin 使用协程时出现NetworkOnMainThreadException,kotlin,kotlin-coroutines,networkonmainthread,Kotlin,Kotlin Coroutines,Networkonmainthread,我一直在尝试在按下按钮时验证网络连接状态。 据此,本守则 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) findViewById<Button>(R.id.button).setOnClickListener { findViewById

我一直在尝试在按下按钮时验证网络连接状态。 据此,本守则

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    findViewById<Button>(R.id.button).setOnClickListener {
        findViewById<TextView>(R.id.logText).setText("Button Pressed"+counter++)
        GlobalScope.launch (Dispatchers.Main) {
            val result  = withContext(Dispatchers.Default){
                isInternetAvailable()
            }
            println(result.toString())
        }
    }
}

suspend fun isInternetAvailable():Boolean {
    return withContext(Dispatchers.Main) {
        try {
            val ipAddr = InetAddress.getByName("google.com")
            //You can replace it with your name
            println("1$ipAddr")
            return@withContext !ipAddr.equals("")
        } catch (e: Exception) {
            println("within exception$e")
            return@withContext false;
        }

    }
}
有人能解释一下NetworkOnMainThread异常的原因吗

非常感谢。

withContext(Dispatchers.Main)
意味着在主线程的lambda中运行代码,这是不允许阻塞代码的。对于网络请求,应使用
Dispatchers.IO

另外,不要使用GlobalScope,因为它会泄露您的活动。使用
lifecycleScope
lifecycleScope
默认情况下使用主线程,因此在使用它时,除非进行阻塞调用,否则不必指定调度程序

在执行阻塞调用时,通常会使挂起函数切换到相应的调度程序,这样您就可以从任何调度程序安全地调用它们。这意味着您的挂起函数不会阻止调用,并且可以从协同程序调用,而无需将它们包装在
withContext

因此,通过以上所有操作,您的代码将变成:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    findViewById<Button>(R.id.button).setOnClickListener {
        findViewById<TextView>(R.id.logText).setText("Button Pressed"+counter++)
        lifecycleScope.launch {
            val result = isInternetAvailable()
            println(result.toString())
        }
    }
}

suspend fun isInternetAvailable(): Boolean {
    return withContext(Dispatchers.IO){
        try {
            val ipAddr = InetAddress.getByName("google.com")
            //You can replace it with your name
            println("1$ipAddr")
            return@withContext !ipAddr.equals("")
        } catch (e: Exception) {
            println("within exception$e")
            return@withContext false;
        }

    }
}
override-fun-onCreate(savedInstanceState:Bundle?){
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById(R.id.button).setOnClickListener{
findviewbyd(R.id.logText).setText(“按下按钮”+计数器++)
生命周期望远镜发射{
val结果=isInternetAvailable()
println(result.toString())
}
}
}
suspend fun isInternetAvailable():布尔值{
返回withContext(Dispatchers.IO){
试一试{
val ipAddr=InetAddress.getByName(“google.com”)
//你可以用你的名字代替它
println(“1$ipAddr”)
return@withContext!ipAddr.equals(“”)
}捕获(e:例外){
println(“例外$e内”)
return@withContext虚假的;
}
}
}
withContext(Dispatchers.Main)
意味着在主线程的lambda中运行代码,这是不允许阻塞代码的。对于网络请求,应使用
Dispatchers.IO

另外,不要使用GlobalScope,因为它会泄露您的活动。使用
lifecycleScope
lifecycleScope
默认情况下使用主线程,因此在使用它时,除非进行阻塞调用,否则不必指定调度程序

在执行阻塞调用时,通常会使挂起函数切换到相应的调度程序,这样您就可以从任何调度程序安全地调用它们。这意味着您的挂起函数不会阻止调用,并且可以从协同程序调用,而无需将它们包装在
withContext

因此,通过以上所有操作,您的代码将变成:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    findViewById<Button>(R.id.button).setOnClickListener {
        findViewById<TextView>(R.id.logText).setText("Button Pressed"+counter++)
        lifecycleScope.launch {
            val result = isInternetAvailable()
            println(result.toString())
        }
    }
}

suspend fun isInternetAvailable(): Boolean {
    return withContext(Dispatchers.IO){
        try {
            val ipAddr = InetAddress.getByName("google.com")
            //You can replace it with your name
            println("1$ipAddr")
            return@withContext !ipAddr.equals("")
        } catch (e: Exception) {
            println("within exception$e")
            return@withContext false;
        }

    }
}
override-fun-onCreate(savedInstanceState:Bundle?){
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById(R.id.button).setOnClickListener{
findviewbyd(R.id.logText).setText(“按下按钮”+计数器++)
生命周期望远镜发射{
val结果=isInternetAvailable()
println(result.toString())
}
}
}
suspend fun isInternetAvailable():布尔值{
返回withContext(Dispatchers.IO){
试一试{
val ipAddr=InetAddress.getByName(“google.com”)
//你可以用你的名字代替它
println(“1$ipAddr”)
return@withContext!ipAddr.equals(“”)
}捕获(e:例外){
println(“例外$e内”)
return@withContext虚假的;
}
}
}