其他
跟着官方文档学习Kotlin协程,官方文档还是香啊!
https://blog.csdn.net/panqf86?type=blog
1. 定义的坑
协程(英语:coroutine)是计算机程序的一类组件,推广了协作式多任务的子程序,允许执行被挂起与被恢复。相对子例程而言,协程更为一般和灵活,但在实践中使用没有子例程那样广泛。协程更适合于用来实现彼此熟悉的程序组件,如协作式多任务、异常处理、事件循环、迭代器、无限列表和管道。
2. 中文文章的坑
1. 英文阅读恐惧症
A coroutine is a concurrency design pattern that you can use on Android to simplify code that executes asynchronously.
On Android, coroutines help to manage long-running tasks that might otherwise block the main thread and cause your app to become unresponsive.
concurrency design pattern(并发设计模式) asynchronously(异步的) long-running tasks(耗时任务) block the main thread(阻塞主线程)
网络请求(也称网络I/O操作) 读写硬盘 CPU计算/耗时操作(列表排序,JSON解析,图片处理等)
原来使用Java开发Android的人还没习惯使用Kotlin来开发Android,更不用说进阶用法Kotlin Coroutines了。不过这点相信过个一年半载将有很大改观。 萌新Android开发者项目经验少,很多都没有经历过老Java Android开发前辈的苦难历程,自然很难对“回调地狱”这样的开发痛点感同身受,结果也基本上是左耳进右耳出。并且关于Kotlin协程的很多中文文章,写得异常繁琐。空有概念却串不到一起,不能融入到自己的知识体系里 。说白了,没有真正入门。
Lightweight(轻量(级)) Fewer memory leaks(更少的内存泄漏(风险)) Built-in cancellation support(内置取消支持) Jetpack integration(jetpack框架集成(支持))
3. 我是这么阅读官方文档的
小节标题隐藏的秘密
Dependency info(依赖信息) Executing in a background thread(运行在后台线程上) Use coroutines for main-safety(使用协程来(保证)主线程安全) Handling exceptions(处理异常)
private val loginRepository: LoginRepository
): ViewModel() {
fun login(username: String, token: String) {
// 启动一个新的 协程 ,并把这个协程放到 后台线程 运行
viewModelScope.launch(Dispatchers.IO) {
val jsonBody = "{ username: \"$username\", token: \"$token\"}"
loginRepository.makeLoginRequest(jsonBody)
}
}
}
launch is a function that creates a coroutine and dispatches the execution of its function body to the corresponding dispatcher.
One issue with the previous example is that anything calling makeLoginRequest needs to remember to explicitly move the execution off the main thread. Let’s see how we can modify the Repository to solve this problem for us.
问题1:如何给一个耗时函数/方法的“脸上”写上“耗时”的标记; 问题2:怎么拿到网络请求的结果(返回值)。
...
suspend fun makeLoginRequest(
jsonBody: String
): Result<LoginResponse> {
// Move the execution of the coroutine to the I/O dispatcher
return withContext(Dispatchers.IO) {
// Blocking network request code
}
}
}
class LoginViewModel(
private val loginRepository: LoginRepository
): ViewModel() {
fun login(username: String, token: String) {
// Create a new coroutine on the UI thread
viewModelScope.launch {
val jsonBody = "{ username: \"$username\", token: \"$token\"}"
// Make the network call and suspend execution until it finishes
val result = loginRepository.makeLoginRequest(jsonBody)
// Display result of the network request to the user
when (result) {
is Result.Success<LoginResponse> -> // Happy path
else -> // Show error in UI
}
}
}
}
is Result.Success<LoginResponse> -> // Happy path
else -> // Show error in UI(把错误信息显示在屏幕上)
}
Once the withContext block finishes, the coroutine in login() resumes execution on the main thread with the result of the network request.
Handling exceptions
private val loginRepository: LoginRepository
): ViewModel() {
fun makeLoginRequest(username: String, token: String) {
viewModelScope.launch {
val jsonBody = "{ username: \"$username\", token: \"$token\"}"
val result = try {
loginRepository.makeLoginRequest(jsonBody)
} catch(e: Exception) {
Result.Error(Exception("Network request failed"))
}
when (result) {
is Result.Success<LoginResponse> -> // Happy path
else -> // Show error in UI
}
}
}
}
Overview小节的总结
英文关键词
其他小节的开始
Inside the body of get, call withContext(Dispatchers.IO) to create a block that runs on the IO thread pool.– Improve app performance with Kotlin coroutines
A CoroutineScope keeps track of any coroutine it creates using launch or async.
repository.refreshTitleWithCallbacks(object : TitleRefreshCallback {
override fun onCompleted() {
_spinner.postValue(false)
}
override fun onError(cause: Throwable) {
_snackBar.postValue(cause.message)
_spinner.postValue(false)
}
})
// 协程的方式实现数据更新,并且可以做到异常处理
fun refreshTitle() {
launchDataLoad {
repository.refreshTitle()
}
}
private fun launchDataLoad(block: suspend () -> Unit) {
viewModelScope.launch {
try {
_spinner.value = true
block()
} catch (error: TitleRefreshError) {
_snackBar.value = error.message
} finally {
_spinner.value = false
}
}
}
Kotlin’s concept of suspending function provides a safer and less error-prone abstraction for asynchronous operations than futures and promises.– Kotlin Coroutines Guide