IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Kotlin - Job 任务/取消 -> 正文阅读

[移动开发]Kotlin - Job 任务/取消

任务取消的状态

仅仅终止线程是一个糟糕的方案,协程的取消能够更好的检查状态关闭释放资源。

  • 运行出错或者调用cancel()后该job会在遇到第一个挂起点开始取消并抛出CancellationException异常(先处于Cancelling状态:isActive=false,isCancelled=true)(没有挂起点便不会响应cancel()操作),之后会调用join()让协程挂起把该job的取消执行完后(再处于Cancelled状态:isCompleted=true,isCancelled=true)才能继续执行其它,否则会存在其它协程并发执行。推荐使用cancelAndJoin()简化调用。
  • 一旦该job被取消,该job下的子job也会一并取消,但父job兄弟job不受影响,该job不能再用作任何新job父job(不能开启新协程)。

Job的状态/函数判断isActive( )isCompleted( )isCancelled( )
New 新创建(optional initial state)falsefalsefalse
Active 活跃(default initial state)truefalsefalse
Completing 完成中(transient state)truefalsefalse
Cancelling 取消中(transient state)falsefalsetrue
Cancelled 已取消(final state)falsetruetrue
Compeleted 已完成(final state)falsetruefalse

任务取消的异常处理

协程通过抛出一个 CancellationException异常 来取消 Job。cancel() 可以传参使用不同的异常来指定原因,需要是 CancellationException 的子类才能取消协程。该异常不会导致父协程或其它子协程的取消,可以使用 try-catch-finally 去捕获处理释放资源,推荐使用标准函数?use() 会自动关闭资源。

suspend fun main() = runBlocking {
    //没有继承父协程的上下文,有自己的作用域,因此 runBlocking 不会等待 GlobalScope 执行完再结束。
    val job = GlobalScope.launch {
        try {
            //耗时操作
        }catch (e:Exception){
            //处理异常
        }finally{
            //释放资源
        }
    }
    delay(1000)  //让job运行一下再取消
//    job.cancel()    //抛异常 JobCancellationException
//    job.join()    //挂起函数,这样就会等 GlobalScope 取消完再继续执行
    job.cancelAndJoin() //简写
}

无法直接取消的任务(CPU密集型、没有挂起点)

由于调用cancel()操作后Job会处于Cancelling状态,此时只需判断Job是否处于活跃状态于便可以响应cancel()操作。

  • CPU密集型任务无法直接被cancel()取消,因为直接取消会丢失临时计算数据。可以通过对Job状态的判断来响应cancel()操作。
  • Job的取消发生在挂起点上,没有挂起点便不会响应cancel()操作,当我们使用协程却没有调用任何挂起函数的时候(做阻塞操作、神经网络学习)便会发生这种情况。

isActive

加在判断里

是一个CoroutineScope的扩展属性,判断Job是否处于活跃状态。

ensureActive()

写在函数里

是一个CoroutineScope的扩展函数,返回coroutineContext扩展函数,调用Job的函数,最终调用的是 !isActive,Job处于非活跃状态就报错CancelllationException。

yield()

不至于抢占太多线程让其它协程拿不到执行权

会检查所在协程的状态,如果已经取消则报错 CancellationException,此外会尝试让出线程执行权。
suspend fun main() = runBlocking {
    val job = launch(Dispatchers.Default) {    //该协程中无挂起点
        while (isActive) {   //判断出false便会取消
            ensureActive()              //检测出false便会取消
            yield()                     //不至于因为任务太抢占资源导致其它协程拿不到线程执行权
            println("CPU密集任务")
        }
    }
    delay(1000)    //让job运行一会儿后再取消
    println("等完")
    job.cancelAndJoin() //cancel()操作会将 isActive = false
    println("结束")
}

一定无法取消的任务

由于我们可以捕获CancellationException异常,在 Job 真正结束前可以做一些事情,由于 Job 响应 cancel() 后已经处于 Cancelling状态,此时启动一个新协程(会被忽略)或者调用挂起函数(会抛异常CancellationException)是无法被执行的。

  • 方式①:指定协程上下文为NonCancellable来得到一个常驻Job不响应 cancel()操作。
  • 方式②:使用invokeOnCompletion()函数,当 Job?处于Cancelled状态Compeleted状态时会执行回调。形参it是一个异常,没有异常值为null,协程被取消值为 CancellationException。
withContext(NonCancellable){ 
    //不会响应取消
}
job.invodeOnCompletion{
    //回调代码
}

CancellableContinuation<T>

suspendCancellableCoroutine

自定义协程取消时所作的操作。

//定义
suspend fun getResource():StudentBean = suspendCancellableCoroutine{ continuation ->
    request(object : ICallBack{
    override fun onSuccess(data:String){
        continuation.resume(data)
    }
    override fun onFailure(exception:Throwable){
        continuation.resumeWithException(exception)
    }
})    
    //定义协程取消时应该做的操作
    continuation.invokeOnCancellation{ //TODO... }
}

//使用
suspend main() = runBlocking{
    try{
        viewModelScope.launch{
            val bean = getResource()
        }
    }catch(e : Exception){
        e.printStackTrace()
    }
}

超时取消的任务?

超时取消Job,报错不处理会导致程序结束。

withTimeout()

public suspend fun <T> withTimeout(timeMillis: Long, block: suspend CoroutineScope.() -> T): T

超时取消,抛出异常会结束程序。

withTimeoutOrNull()

public suspend fun <T> withTimeoutOrNull(timeMillis: Long, block: suspend CoroutineScope.() -> T): T??

超时取消并返回null,替代抛出异常。

withTimeout(1000) {
    println("")
}
withTimeoutOrNull(1000) {
    println("")
} ?: "值为空"
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-07-21 21:40:09  更:2022-07-21 21:40:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 3:41:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码