Android和Kotlin noob在这里-我有一个调用SOAP Web服务的应用程序。现在,调用是使用Thread进行的,并且通讯正常。我想将其移至Kotlin协程或Android Async任务,我的问题是-在这种情况下哪个更好?
我已经尝试根据本文创建协程调用https://proandroiddev.com/how-to-make-sense-of-kotlin-coroutines-b666c7151b93,基本上适应了这种模式:
fun main() = runBlocking {
val deferredResult = async {
delay(1000L)
"World!"
}
println("Hello, ${deferredResult.await()}")
}
[当我将Web服务调用放入协程异步时,然后Android Studio突出显示HttpTransportSE调用方法(http://www.kobjects.org/ksoap2/doc/api/org/ksoap2/transport/HttpTransportSE.html),并显示以下警告:
不合适的阻塞方法调用。报告在不应阻止线程的代码片段中找到的线程阻止方法调用”
我对这条消息的理解是HttpTransportSE进行的调用会阻塞线程,因此我们失去了使用协程的优势,我应该坚持执行Async任务。这种解释是正确的,还是有一种用协程将通话包裹起来的方法,这种方法会更有效?
下面是我的代码(它与Web服务通信,但是由于警告,我感觉这不是执行此操作的适当方法):
fun callWebService(
...
): String {
val defferedResult: Deferred<String> = GlobalScope.async {
try {
...
val envelope = SoapSerializationEnvelope(SoapEnvelope.VER12)
...
val androidHttpTransport = HttpTransportSE(URL)
androidHttpTransport.debug = true
androidHttpTransport.call("$NAMESPACE/$methodName", envelope) //this is where I get the warning
val resultData = envelope.response
webResponse = "$resultData"
...
}
return@async webResponse
}
return runBlocking { defferedResult.await() }
}
由于这个article,我想我已经知道了归结为背景(以我为例Dispatchers.IO
)SOAP调用可以是常规函数,不需要Deffered等。
我正在将MVVM模型与存储库一起使用,因此所有后台工作都在Repository
级别上进行,使用相应Fragment
中定义的功能从ViewModel
启动,并且范围有限
我的SOAP调用现在看起来像这样
fun callWebService(...): String {
try {
...
val envelope = SoapSerializationEnvelope(SoapEnvelope.VER12)
...
val androidHttpTransport = HttpTransportSE(URL)
androidHttpTransport.debug = true
androidHttpTransport.call("$NAMESPACE/$methodName", envelope)
val resultData = envelope.response
webResponse = "$resultData"
...
}
return webResponse
}
在Repository
中,我具有以下功能-注意suspend
和Dispatchers.IO
suspend fun insertAndSend(task: Task) {
withContext(Dispatchers.IO) {
val response = callWebService(processedTask)
processedTask.status = response
taskDao.update(processedTask)
}
}
在ViewModel
中,我在Repository
中调用了ViewModelScope
函数
//defined in ViewModel class
fun insertAndSend(task: Task) = viewModelScope.launch { repository.insertAndSend(task) }
通过按下按钮在相应的Fragment
中触发