1.取消协程的执行
在一个⻓时间运行的应用程序中,你也许需要对你的后台协程进行细粒度的控制。比如说,一个用戶也许关闭了 一个启动了协程的界面,那么现在协程的执行结果已经不再被需要了,这时,它应该是可以被取消的。该 launch 函数返回了一个可以被用来取消运行中的协程的 Job:
image.png一旦main函数调用了 job.cancel,我们在其它的协程中就看不到任何输出,因为它被取消了。这里也有一 个可以使 Job 挂起的函数 cancelAndJoin 它合并了对 cancel 以及 join 的调用。
2.取消是协作的
协程的取消是 协作 的。一段协程代码必须协作才能被取消。所有 kotlinx.coroutines 中的挂起函数都是 可被取消的 。它们检查协程的取消,并在取消时抛出 CancellationException。然而,如果协程正在执行计算任务,并且没有检查取消的话,那么它是不能被取消的,就如如下示例代码所示:
image.png运行结果:
image.png当协程可以被取消时,取消协程为什么没有抛出CancellationException异常呢?
image.png3.使计算代码可取消
检查取消状态,
image.png调用cancelAndJoin()时会改变isActive的值,所以while循环就会退出
运行结果:
image.png4.在 finally 中释放资源
image.png运行结果:
image.png5.运行不能取消的代码块
在前一个例子中任何尝试在 finally 块中调用挂起函数的行为都会抛出 CancellationException,因为这里 持续运行的代码是可以被取消的。
image.png运行结果:
image.png在finally中执行挂起函数delay会抛出异常,所以运行结果只打印了job: I'm running finally1,没有打印job: I'm running finally2
通常,这并不是一个问题,所有良好的关闭操作(关闭一个文件、取消一个作 业、或是关闭任何一种通信通道)通常都是非阻塞的,并且不会调用任何挂起函数。然而,在真实的案例中,当你 需要挂起一个被取消的协程,你可以将相应的代码包装在 withContext(NonCancellable) {......} 中,并 使用 withContext 函数以及 NonCancellable 上下文,如下示例所示:
image.png运行结果:
image.png6.超时
在实践中绝大多数取消一个协程的理由是它有可能超时。当你手动追踪一个相关 Job 的引用并启动了一个单独 的协程在延迟后取消追踪,这里已经准备好使用 withTimeout 函数来做这件事。如下代码:
image.png运行结果:
image.pngwithTimeout 抛出了 TimeoutCancellationException ,它是 CancellationException 的子类。我们之前 没有在控制台上看到堆栈跟踪信息的打印。这是因为在被取消的协程中 CancellationException 被认为 是协程执行结束的正常原因。
由于取消只是一个例外,所有的资源都使用常用的方法来关闭。如果你需要做一些各类使用超时的特别的额外操作,可以使用类似 withTimeout 的 withTimeoutOrNull 函数,并把这些会超时的代码包装在 try {...} catch (e: TimeoutCancellationException) {...} 代码块中,而 withTimeoutOrNull 通过返回
null 来进行超时操作,从而替代抛出一个异常:
7.资源的异步超时
初始化资源时,如果在规定时间内资源没有初始化(获取资源)完成,则会抛出超时异常,之后的释放资源的操作就不会执行,这样就会导致内存泄漏,如下代码
image.png如果运行的结果不为0,则表示有内存泄漏
如何避免这种内存泄漏呢?
将释放资源的操作放在finally中
网友评论