Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin 如何制作;不适当的阻塞方法调用“;适当的_Kotlin_Okhttp_Kotlin Coroutines_Moshi - Fatal编程技术网

Kotlin 如何制作;不适当的阻塞方法调用“;适当的

Kotlin 如何制作;不适当的阻塞方法调用“;适当的,kotlin,okhttp,kotlin-coroutines,moshi,Kotlin,Okhttp,Kotlin Coroutines,Moshi,我目前正在尝试更多地利用kotlin协同程序。但我面临一个问题:当在这些协同路由中使用moshi或okhttp时,我得到一个警告: “不适当的阻止方法调用” 解决这些问题的最佳方法是什么?我真的不想显得不合适;-) 警告是关于阻止当前线程和协同程序的方法无法正确挂起。这样,您将失去协同路由的所有好处,并再次降级为每个线程一个作业 每个案件都应以不同的方式处理。对于可挂起的http调用,可以使用。但有时您的案例没有库,因此您可以编写自己的解决方案,也可以忽略此警告 编辑:withContext(D

我目前正在尝试更多地利用kotlin协同程序。但我面临一个问题:当在这些协同路由中使用moshi或okhttp时,我得到一个警告:

“不适当的阻止方法调用”


解决这些问题的最佳方法是什么?我真的不想显得不合适;-)

警告是关于阻止当前线程和协同程序的方法无法正确挂起。这样,您将失去协同路由的所有好处,并再次降级为每个线程一个作业

每个案件都应以不同的方式处理。对于可挂起的http调用,可以使用。但有时您的案例没有库,因此您可以编写自己的解决方案,也可以忽略此警告


编辑:
withContext(Dispatchers.IO)
或一些自定义调度器可用于解决此问题。感谢您的评论。

调用带有
@Throws(IOException::class)
(Kotlin 1.3.61)注释的挂起函数时,您也会收到此警告。不确定这是否是有意的。无论如何,您可以通过删除该注释或将其更改为
异常
类来抑制此警告。

使用
与上下文
另一上下文中包装代码中的“不当阻止方法调用”

也就是说(例如):

如果正在执行读/写阻塞方法调用:

val objects = withContext(Dispatchers.IO) { dao.getAll() }
如果您正在执行阻塞网络请求(使用改装):

或者,如果您正在执行CPU密集型阻塞任务:

val sortedUsers = withContext(Dispatchers.Default) { users.sortByName() }

这将暂停当前协同程序,然后在不同的线程上执行“不适当的阻塞调用”(从
Dispatchers.IO
Dispatchers.Default
池),因此,不会阻塞执行协同程序的线程。

如果您确实像一些答案所建议的那样选择抑制,请使用


@Suppress(“BlockingMethodInNonBlockingContext”)
我使用的是Android Studio 4.1,当我使用
Moshi
或操纵
文件时会显示警告。即使我确定自己在做什么,用上下文将代码包装在
中也无济于事


我最近发现,将发出警告的小代码移动到标准方法中,而不使用
suspend
fun action(){…}
可以删除警告。这很难看,因为它只是隐藏了警告。

可能会发生异常,这就是它显示此警告的原因。使用
runCatching{}
。它捕获从块函数执行中抛出的任何可丢弃异常,并将其封装为失败

例如:

 CoroutineScope(Dispatchers.IO).launch {
         runCatching{
               makeHttpRequest(URL(downloadLocation))
         }
}

忽略警告几乎从来都不是正确的事情,你至少可以在
withContext(Dispatchers.IO)
中运行阻塞代码。如果你在
withContext(Dispatchers.IO)
中运行阻塞代码,那么它就不再阻塞,警告也不正确了,对吗?@noloman好问题,因为“至少”假设问这个问题的人不知道。当您引入这个包装器时,警告仍然没有消失。@Tenfour04因此,如果我们将代码包装在
withContext(Dispatchers.IO)
中,那么警告是不正确的?AndroidStudio仍然会为我显示它,除非我放弃挂起并改用
运行阻塞(Dispatchers.IO)
。添加
withContext(Dispatchers…)
并没有删除警告让我们称之为抑制,而不是修复:)我想,静态分析器之所以突出显示它,是因为抛出IOException的方法通常是阻塞的,并且需要花费一些宝贵的时间来完成。我发现关于IOException的这个解释很有帮助:我使用了一个在
Dispatchers.IO
中运行代码的助手类。尽管如此,它还是在
val response=someMethod().execute
response.body()?.string()中显示了警告。所以,我只是抑制了警告,我不明白。我尝试使用Dispatchers.IO,但它仍然显示警告。我添加了
Thread.sleep
来模拟长时间的等待。我希望能够通过使用线程的任何方式(中断和检查是否取消)取消它。这个问题与Kotlin协程(异步编程)有关。如果使用
Thread.sleep
,则直接操作底层(Java体系结构)线程。在协程作用域内使用
suspendCoroutine
函数,使协程等待作业完成,同时底层线程可以继续执行其他协程。由于thread.sleep是函数的一种有效情况(可以在我调用的函数中执行,例如,我无法控制它们内部的内容),我不能替换它。你能分享给出警告的代码吗?添加上面的内容和上下文都不起作用。尽管如此,这看起来仍然像是一个黑客或利用漏洞来绕过Kotlin插件对不适当的阻塞调用的错误检测。因为这个方法基本上只是将有问题的调用包装在一个
try。。。捕捉
块,以某种方式使其对检查不可见。
 CoroutineScope(Dispatchers.IO).launch {
         runCatching{
               makeHttpRequest(URL(downloadLocation))
         }
}