先决条件:
- Android上的Kotlin协程
- 在Kotlin Coroutines中启动vs异步
众所周知,异步和启动是启动协程的两种方式。由于已知使用异步来获取结果,因此仅在需要并行执行时才使用&,而当我们不想获取结果时使用launch并用于诸如更新之类的操作我们知道异步是到目前为止启动协程并获取结果的唯一方法,但是当我们不想进行并行网络调用时,就会出现异步问题。已知使用异步时,需要使用异步 await()函数导致主线程被阻塞,但是withContext的概念消除了阻塞主线程的问题。
withContext只是编写异步方法的另一种方式,其中不必编写await() 。使用withContext时,它将串行而不是并行运行任务。因此,应该记住,当我们在后台执行单个任务并想获取该任务的结果时,应该使用withContext。让我们以一个示例来演示withContext的工作方式:
Kotlin
// two kotlin suspend functions
// Suppose we have two tasks like below
private suspend fun doTaskOne(): String
{
delay(2000)
return "One"
}
private suspend fun doTaskTwo(): String
{
delay(2000)
return "Two"
}
Kotlin
// kotlin function using async
fun startLongRunningTaskInParallel()
{
viewModelScope.launch
{
val resultOneDeferred = async { TaskOne() }
val resultTwoDeferred = async { TaskTwo() }
val combinedResult = resultOneDeferred.await() + resultTwoDeferred.await()
}
}
Kotlin
// kotlin function using withContext
fun startLongRunningTaskInParallel()
{
viewModelScope.launch
{
val resultOne = withContext(Dispatchers.IO) { TaskOne() }
val resultTwo = withContext(Dispatchers.IO) { TaskTwo() }
val combinedResult = resultOne + resultTwo
}
}
Kotlin
// sample kotlin program for complete
// demonstration of withContext
fun testWithContext
{
var resultOne = "GFG"
var resultTwo = "Is Best"
Log.i("withContext", "Before")
resultOne = withContext(Dispatchers.IO) { function1() }
resultTwo = withContext(Dispatchers.IO) { function2() }
Log.i("withContext", "After")
val resultText = resultOne + resultTwo
Log.i("withContext", resultText)
}
suspend fun function1(): String
{
delay(1000L)
val message = "function1"
Log.i("withContext", message)
return message
}
suspend fun function2(): String
{
delay(100L)
val message = "function2"
Log.i("withContext", message)
return message
}
让我们使用async-await并行运行两个任务,然后使用withcontext看看两者之间的区别。
科特林
// kotlin function using async
fun startLongRunningTaskInParallel()
{
viewModelScope.launch
{
val resultOneDeferred = async { TaskOne() }
val resultTwoDeferred = async { TaskTwo() }
val combinedResult = resultOneDeferred.await() + resultTwoDeferred.await()
}
}
在这里使用异步,两个任务并行运行。现在,让我们使用withContext并与withContext串联执行相同的任务。
科特林
// kotlin function using withContext
fun startLongRunningTaskInParallel()
{
viewModelScope.launch
{
val resultOne = withContext(Dispatchers.IO) { TaskOne() }
val resultTwo = withContext(Dispatchers.IO) { TaskTwo() }
val combinedResult = resultOne + resultTwo
}
}
在这里可以看到,在withContext中,所有内容都是相同的,唯一的区别是,这里我们不必使用await()函数,并且任务以串行方式执行。由于这里执行了多个任务,因此应该记住异步应该与多个任务一起使用,而withContext应该与单个任务一起使用。现在让我们举一个例子,尝试详细了解withContext及其执行方式。
科特林
// sample kotlin program for complete
// demonstration of withContext
fun testWithContext
{
var resultOne = "GFG"
var resultTwo = "Is Best"
Log.i("withContext", "Before")
resultOne = withContext(Dispatchers.IO) { function1() }
resultTwo = withContext(Dispatchers.IO) { function2() }
Log.i("withContext", "After")
val resultText = resultOne + resultTwo
Log.i("withContext", resultText)
}
suspend fun function1(): String
{
delay(1000L)
val message = "function1"
Log.i("withContext", message)
return message
}
suspend fun function2(): String
{
delay(100L)
val message = "function2"
Log.i("withContext", message)
return message
}
函数比函数1更快,因为函数2 2个执行具有更少的延迟,然后函数,由于withContext是暂停通话,那就是它不会去下一行,直到它完成。由于withContext是一个挂起调用,并且不会阻塞主线程,因此我们可以在IO线程忙于执行function1和函数 2的同时执行其他任务。