2019-12-02 21:21:39.615 21445-21445/com.example.android.kotlincoroutines D/MainViewModel: test in IO thread: Thread[main,5,main] 2019-12-02 21:21:40.620 21445-21445/com.example.android.kotlincoroutines D/MainViewModel: do we really sleep about 1000ms? Thread[main,5,main]
suspendfuntest() : String { viewModelScope.async { Log.d(TAG, "test in IO thread: " + Thread.currentThread()) delay(1_000) Log.d(TAG, "do we really sleep about 1000ms? " + Thread.currentThread()) }.await() return"Test" }
/** * Wait one second then display a snackbar. */ funonMainViewClicked() {
viewModelScope.launch { val rst = test() _snackBar.postValue(rst) } }
我们会发现一旦调用了 await(),编译器就会要求我们声明 test 为 suspend 函数,原因很简单。如上文所述,await()是被声明为 suspend,它被声明为耗时函数,那么你需要放在一个 suspend 函数去调用
结果:
1 2
2019-12-02 21:26:10.198 21809-21809/com.example.android.kotlincoroutines D/MainViewModel: test in IO thread: Thread[main,5,main] 2019-12-02 21:26:11.202 21809-21809/com.example.android.kotlincoroutines D/MainViewModel: do we really sleep about 1000ms? Thread[main,5,main]
postValue 将会在第二条日志打印时调用,满足延时效果
withContext()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
suspendfuntest() : String { withContext(viewModelScope.coroutineContext) { Log.d(TAG, "test in IO thread: " + Thread.currentThread()) delay(1_000) Log.d(TAG, "do we really sleep about 1000ms? " + Thread.currentThread()) } return"Test"
} /** * Wait one second then display a snackbar. */ funonMainViewClicked() {
viewModelScope.launch { val rst = test() _snackBar.postValue(rst) } }
funshowUser() { viewModelScope.launch { val user = getUser() // Main Thread _user.postValue(user) } }
我们认为network.fetchUser()是一个耗时操作,那么我们用 withContext(Dispatchers.IO)包裹起来,丢给 IO 线程处理,当 network.fetchUser()返回时,withContext 自动将线程切回 MAIN 线程,回到 showUser()的 user 变量处,这里也是 MAIN 线程