既然已经有很多好的答案了,我想给其他人一个更简单的例子。
runBlocking用例:
myMethod() is suspend function
runBlocking { } starts a Coroutine in blocking way. It is similar to how we were blocking normal threads with Thread class and notifying blocked threads after certain events.
runBlocking { } does block the current executing thread, until the coroutine (body between {}) gets completed
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
Log.i(TAG,"Outer code started on Thread : " + Thread.currentThread().name);
runBlocking {
Log.d(TAG,"Inner code started on Thread : " + Thread.currentThread().name + " making outer code suspend");
myMethod();
}
Log.i(TAG,"Outer code resumed on Thread : " + Thread.currentThread().name);
}
private suspend fun myMethod() {
withContext(Dispatchers.Default) {
for(i in 1..5) {
Log.d(TAG,"Inner code i : $i on Thread : " + Thread.currentThread().name);
}
}
输出:
I/TAG: Outer code started on Thread : main
D/TAG: Inner code started on Thread : main making outer code suspend
// ---- main thread blocked here, it will wait until coroutine gets completed ----
D/TAG: Inner code i : 1 on Thread : DefaultDispatcher-worker-2
D/TAG: Inner code i : 2 on Thread : DefaultDispatcher-worker-2
D/TAG: Inner code i : 3 on Thread : DefaultDispatcher-worker-2
D/TAG: Inner code i : 4 on Thread : DefaultDispatcher-worker-2
D/TAG: Inner code i : 5 on Thread : DefaultDispatcher-worker-2
// ---- main thread resumes as coroutine is completed ----
I/TAG: Outer code resumed on Thread : main
启动用例:
launch { } starts a coroutine concurrently.
This means that when we specify launch, a coroutine starts execution on worker thread.
The worker thread and outer thread (from which we called launch { }) both runs concurrently. Internally, JVM may perform Preemptive Threading
When we require multiple tasks to run in parallel, we can use this. There are scopes which specify lifetime of coroutine. If we specify GlobalScope, the coroutine will work until application lifetime ends.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
Log.i(TAG,"Outer code started on Thread : " + Thread.currentThread().name);
GlobalScope.launch(Dispatchers.Default) {
Log.d(TAG,"Inner code started on Thread : " + Thread.currentThread().name + " making outer code suspend");
myMethod();
}
Log.i(TAG,"Outer code resumed on Thread : " + Thread.currentThread().name);
}
private suspend fun myMethod() {
withContext(Dispatchers.Default) {
for(i in 1..5) {
Log.d(TAG,"Inner code i : $i on Thread : " + Thread.currentThread().name);
}
}
}
输出:
10806-10806/com.example.viewmodelapp I/TAG: Outer code started on Thread : main
10806-10806/com.example.viewmodelapp I/TAG: Outer code resumed on Thread : main
// ---- In this example, main had only 2 lines to execute. So, worker thread logs start only after main thread logs complete
// ---- In some cases, where main has more work to do, the worker thread logs get overlap with main thread logs
10806-10858/com.example.viewmodelapp D/TAG: Inner code started on Thread : DefaultDispatcher-worker-1 making outer code suspend
10806-10858/com.example.viewmodelapp D/TAG: Inner code i : 1 on Thread : DefaultDispatcher-worker-1
10806-10858/com.example.viewmodelapp D/TAG: Inner code i : 2 on Thread : DefaultDispatcher-worker-1
10806-10858/com.example.viewmodelapp D/TAG: Inner code i : 3 on Thread : DefaultDispatcher-worker-1
10806-10858/com.example.viewmodelapp D/TAG: Inner code i : 4 on Thread : DefaultDispatcher-worker-1
10806-10858/com.example.viewmodelapp D/TAG: Inner code i : 5 on Thread : DefaultDispatcher-worker-1
异步和等待用例:
When we have multiple tasks to do and they depend on other's completion, async and await would help.
For example, in below code, there are 2 suspend functions myMethod() and myMethod2(). myMethod2() should get executed only after full completion of myMethod() OR myMethod2() depends on result of myMethod(), we can use async and await
async starts a coroutine in parallel similar to launch. But, it provides a way to wait for one coroutine before starting another coroutine in parallel.
That way is await(). async returns an instance of Deffered<T>. T would be Unit for default. When we need to wait for any async's completion, we need to call .await() on Deffered<T> instance of that async. Like in below example, we called innerAsync.await() which implies that the execution would get suspended until innerAsync gets completed. We can observe the same in output. The innerAsync gets completed first, which calls myMethod(). And then next async innerAsync2 starts, which calls myMethod2()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
Log.i(TAG,"Outer code started on Thread : " + Thread.currentThread().name);
job = GlobalScope.launch(Dispatchers.Default) {
innerAsync = async {
Log.d(TAG, "Inner code started on Thread : " + Thread.currentThread().name + " making outer code suspend");
myMethod();
}
innerAsync.await()
innerAsync2 = async {
Log.w(TAG, "Inner code started on Thread : " + Thread.currentThread().name + " making outer code suspend");
myMethod2();
}
}
Log.i(TAG,"Outer code resumed on Thread : " + Thread.currentThread().name);
}
private suspend fun myMethod() {
withContext(Dispatchers.Default) {
for(i in 1..5) {
Log.d(TAG,"Inner code i : $i on Thread : " + Thread.currentThread().name);
}
}
}
private suspend fun myMethod2() {
withContext(Dispatchers.Default) {
for(i in 1..10) {
Log.w(TAG,"Inner code i : $i on Thread : " + Thread.currentThread().name);
}
}
}
输出:
11814-11814/? I/TAG: Outer code started on Thread : main
11814-11814/? I/TAG: Outer code resumed on Thread : main
11814-11845/? D/TAG: Inner code started on Thread : DefaultDispatcher-worker-2 making outer code suspend
11814-11845/? D/TAG: Inner code i : 1 on Thread : DefaultDispatcher-worker-2
11814-11845/? D/TAG: Inner code i : 2 on Thread : DefaultDispatcher-worker-2
11814-11845/? D/TAG: Inner code i : 3 on Thread : DefaultDispatcher-worker-2
11814-11845/? D/TAG: Inner code i : 4 on Thread : DefaultDispatcher-worker-2
11814-11845/? D/TAG: Inner code i : 5 on Thread : DefaultDispatcher-worker-2
// ---- Due to await() call, innerAsync2 will start only after innerAsync gets completed
11814-11848/? W/TAG: Inner code started on Thread : DefaultDispatcher-worker-4 making outer code suspend
11814-11848/? W/TAG: Inner code i : 1 on Thread : DefaultDispatcher-worker-4
11814-11848/? W/TAG: Inner code i : 2 on Thread : DefaultDispatcher-worker-4
11814-11848/? W/TAG: Inner code i : 3 on Thread : DefaultDispatcher-worker-4
11814-11848/? W/TAG: Inner code i : 4 on Thread : DefaultDispatcher-worker-4
11814-11848/? W/TAG: Inner code i : 5 on Thread : DefaultDispatcher-worker-4
11814-11848/? W/TAG: Inner code i : 6 on Thread : DefaultDispatcher-worker-4
11814-11848/? W/TAG: Inner code i : 7 on Thread : DefaultDispatcher-worker-4
11814-11848/? W/TAG: Inner code i : 8 on Thread : DefaultDispatcher-worker-4
11814-11848/? W/TAG: Inner code i : 9 on Thread : DefaultDispatcher-worker-4
11814-11848/? W/TAG: Inner code i : 10 on Thread : DefaultDispatcher-worker-4