Kotlin在进入下一个索引之前等待循环中的协同程序



嗨,我正在使用for循环来调用一个协程方法(调用改装(,对于每个循环,我都希望协程方法完成(改装响应后(,但我的循环似乎一直在进行,而没有等待协程方法结束。。。下面是我的循环方法:-

fun forwardFailedSMS(context: Context) {
var failed = getFailedSms(context)
failed.forEachIndexed { index, f ->    
println("NOW ${index}")
GlobalScope.launch(Dispatchers.IO) {
var time = measureTimeMillis {
val fn = async {
callForwardAPI(context, f)
}
val result = fn.await()
}
}
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//I want the above to finish before going to next index...
}
refreshSmsList(context!!)
}

下面是callForwardAPI函数,该函数使用改装来调用API:-

suspend fun callForwardAPI(context: Context,sms: SmsData) {
val databaseHandler: DatabaseHandler = DatabaseHandler(context)
val retrofit = Retrofit.Builder()
.baseUrl("https://backend.mydomain.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(SMSService::class.java)
val api = GlobalScope.async {
val response = retrofit.postForwardSMS(
sms.sender,
sms.message
).awaitResponse()
if (response.isSuccessful) {
println("DONE SUCCESS ${sms.message}")
}
}
api.await()
}

日志";现在";循环并在";完成成功";对于特定的循环打印。。。

您必须将.launch{ }方法移动到forEach之外。目前发生的情况是,您的suspend方法将被挂起,但在启动内部,因此for可以继续。

如果你将发射移动到for之外,你的for循环也将在每个暂停点暂停

您的服务调用包含协程,因此,您不需要在forwardFailedSMS函数中使用协程。您正在创建两个独立的异步作业。我认为使用实时数据观察者可以解决您的问题。

您需要更改如下所示的forwardFailedSMS功能:

lateinit var failedListSize: Int
lateinit var serviceCallResponseCount: Int
fun forwardFailedSMS(context: Context) {
var failed = getFailedSms(context)
failedListSize = failed.size
serviceCallResponseCount = 0
failed.forEachIndexed { index, f ->    
println("NOW ${index}")
callForwardAPI(context, f)
}

}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// I assume that you are using viewmodel and fragment. If you use another pattern, you can change onViewCreate to another lifecycle function.
viewModel.myLiveData.observe(viewLifeCycleOwner, Observer{
println("NOW ${index} observed response")
serviceCallResponseCount++
if (serviceCallResponseCount == failedListSize){
refreshSmsList(context!!)
}
}
}

并将您的callForwardAPI发送到:

val myLiveData: MutableLiveData<QueryOnlinePolicyResponse> = MutableLiveData()
suspend fun callForwardAPI(context: Context,sms: SmsData) {
val databaseHandler: DatabaseHandler = DatabaseHandler(context)
val retrofit = Retrofit.Builder()
.baseUrl("https://backend.mydomain.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(SMSService::class.java)
val api = GlobalScope.async {
val response = retrofit.postForwardSMS(
sms.sender,
sms.message
).awaitResponse()
// I put postValue here because we are waiting same response count with fail in our observer
myLiveData.postValue(response)
if (response.isSuccessful) {
println("DONE SUCCESS ${sms.message}")
}
}
api.await()
}

我相信这种模式会解决你的案子。我无法尝试,我使用编辑器。如果有一些错误,请原谅我。

如果希望forwardFailedSMS()保持常规阻塞方法,可以使用runBlocking而不是launchasync

...
runBlocking(Dispatchers.IO) {
failed.forEachIndexed { index, f ->    
println("NOW ${index}")
callForwardAPI(context, f)
}
}
...

最新更新