2. 线程 & 协程
有的人会将协程比喻成:线程的封装框架。从宏观角度看,这有一定道理,当然,Kotlin 官方并没有这么宣传过。
从微观角度上看,协程有点像轻量级的线程
。协程能轻量到什么程度?就算你在一个线程中创建1000
个协程,也不会有什么影响。
从包含关系上看,协程跟线程的关系,有点像“线程与进程的关系”,毕竟,协程不可能脱离线程运行。
协程虽然不能脱离线程而运行,但可以在不同的线程之间切换。看到这,大家应该能理解本文最开始放的那张动图的含义了吧?
说了这么多协程的好,但就凭它的”高效“,”轻量“我们就要用吗?汇编语言也很高效啊。C 语言也能写出轻量的程序啊。
高效和轻量,都不是 Kotlin 协程的核心竞争力。
Kotlin 协程的核心竞争力在于:它能简化异步并发
任务。
作为 Java 开发者,我们很清楚线程并发
是多么的危险,写出来的异步代码是多么的难以维护。
3. 异步代码 & 回调地狱
以一段简单的 Java 代码为例,我们发起了一个异步请求,从服务端查询用户的信息,通过 CallBack 返回 response:
getUserInfo(new CallBack() {
@Override
public void onSuccess(String response) {
if (response != null) {
System.out.println(response);
}
}
});
到目前为止,我们的代码看起来并没有什么问题,但如果我
《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
们的需求变成了这样呢?
查询用户信息 --> 查找该用户的好友列表 -->拿到好友列表后,查找该好友的动态
getUserInfo(new CallBack() {
@Override
public void onSuccess(String user) {
if (user != null) {
System.out.println(user);
getFriendList(user, new CallBack() {
@Override
public void onSuccess(String friendList) {
if (friendList != null) {
System.out.println(friendList);
getFeedList(friendList, new CallBack() {
@Override
public void onSuccess(String feed) {
if (feed != null) {
System.out.println(feed);
}
}
});
}
}
});
}
}
});
有点恶心了,是不是?这还是仅包含 onSuccess 的情况,实际情况会更复杂,因为我们还要处理异常,处理重试,处理线程调度,甚至还可能涉及多线程同步。
4. 地狱到天堂:协程
今天的主角是协程,上面的代码用协程应该写?很简单,核心就是三行代码:
val user = getUserInfo()
val friendList = getFriendList(user)
val feedList = getFeedList(friendList)
是不是简洁到了极致?这就是 Kotlin 协程的魅力:以同步的方式完成异步任务
。
4-1 使用协程的要点
上面的代码之所以能写成类似同步
的方式,关键还是在于那三个请求函数的定义。与普通函数不同的地方在于,它们都被 suspend
修饰,这代表它们都是:挂起函数
。
// delay(1000L)用于模拟网络请求
//挂起函数
// ↓
suspend fun getUserInfo(): String {
withContext(Dispatchers.IO) {
delay(1000L)
}
return “BoyCoder”
}
//挂起函数
// ↓
suspend fun getFriendList(user: String): String {
withContext(Dispatchers.IO) {
delay(1000L)
}
return “Tom, Jack”
}
//挂起函数
// ↓
suspend fun getFeedList(list: String): String {
withContext(Dispatchers.IO) {
delay(1000