协程的挂起与恢复

原理

遇到挂起函数时,会首先返回一个对象(协程内部定义的一个单例类),然后将协程封装成 Continuation 对象传递至挂起函数中,挂起函数需要返回真正结果时再调用 Continuation 的 resumeWith 方法,恢复协程的执行。

Continuation 内部会通过状态机(其实就一个 int 型变量)控制回调时开始执行的位置。这就是挂起与恢复的 Java 实现。

finally 代码块

java 中的 finnaly 比较特殊,即使在 try 中使用了 return 语句,finally 也一定会执行。

那如果 try 中调用了挂起函数,finally 代码块该在何时执行呢?答案是在挂起函数返回真正结果后执行,与调用普通函数一致

原因是:由 kt 生成的 java 代码中并没有使用 finnaly,finally 代码块会放在所有代码后执行

如下绿框中的代码是 finally 代码块中的代码,可以发现它被放到了 invokeSuspend 的最后面,保证是在最后执行

使用 finally 时可能会存在一个问题:如果在 finally 中使用协程,该协程有可能不会被执行。原因在于:如果 try 中代码期间协程被取消了,那么 finally 中的协程就不会在执行(协程不会运行在已取消的 scope 中)。

如下:在 try 执行时如果协程被取消了,deleteFile 永远不会执行到。

kotlin 复制代码
viewModelScope.launch {
    try {
        file.deleteOnExit()
        file.createNewFile()
        val consume = write(file)
    } finally {
        deleteFile(file)
    }
}

解决方式是在 deleteFile 外层使用 withContext(NonCancellable)包裹,但要注意使用该方式时一定要注意内存泄露等:因为该作用域内的协程已经脱离的掌控,没有办法进行取消了。

kotlin 复制代码
withContext(NonCancellable) {
    deleteFile(file)
}
相关推荐
Kapaseker5 小时前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴5 小时前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭15 小时前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab16 小时前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
BoomHe21 小时前
Now in Android 架构模式全面分析
android·android jetpack
二流小码农1 天前
鸿蒙开发:上传一张参考图片便可实现页面功能
android·ios·harmonyos
鹏程十八少1 天前
4.Android 30分钟手写一个简单版shadow, 从零理解shadow插件化零反射插件化原理
android·前端·面试
Kapaseker1 天前
一杯美式搞定 Kotlin 空安全
android·kotlin
三少爷的鞋1 天前
Android 协程时代,Handler 应该退休了吗?
android
火柴就是我2 天前
让我们实现一个更好看的内部阴影按钮
android·flutter