Android 面试之Kotlin 协程上下文和异常处理

本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点

上下文是什么

CoroutineContext是一组用于定义协程行为的元素,包括以下几部分:

  • Job:控制协程的生命周期
  • CoroutineDispatcher:向合适的线程分发任务
  • CoroutineName:协程的名称,调试的时候很有用
  • CoroutineExceptionHandler:处理未被捕获的异常
  • 这几个部分可以通过"+"来组合
@Test
fun `test coroutine context`() = runBlocking {
    launch(Dispatchers.IO + CoroutineName("test")) {
        println("thread: ${Thread.currentThread().name}")
    }
}
协程上下文的继承
  • 对于新创建的协程,它的CoroutineContext会包含一个全新的Job实例,它会帮助我们控制协程的生命周期。
  • 剩下的元素会从CoroutineContext的父类继承,该父类可能是另外一个协程或者创建该协程的CoroutineScope

协程的上下文 = 默认值 + 继承的CoroutineContext + 参数

  • 一些元素包含默认值:Dispatchers.Default是默认的CoroutineDispatcher,以及“coroutine”作为默认的CoroutineName
  • 继承的CoroutineContext是CoroutineScope或是其父协程的CoroutineContext
  • 传入协程构建器的参数的优先级高于继承的上下文参数,因此会覆盖对应的参数值
@Test
fun `test coroutine context extend`() = runBlocking {
    val coroutineExceptionHandler = CoroutineExceptionHandler { _, throwable -> 
        println("handle exception: $throwable")
    }
    //scope有了新的CoroutineContext,和runBlocking不一样
    val scope = CoroutineScope(Job() + Dispatchers.Main + coroutineExceptionHandler)
    //job的CoroutineContext继承自scope,但是Job会是新的,每个协程都会有新的Job
    val job = scope.launch(Dispatchers.IO) { 
        //新协程
    }
}

由于传入协程构建器的参数优先级更高,所以job的调度器被覆盖,是Dispatchers.IO而不是父类的Dispatchers.Main

异常
异常的传播

协程构建器有2种传播形式:

  • 自动传播异常(launch和actor)、向用户暴露异常(async和produce)
  • 当这些构建器用于创建一个根协程时(该协程不是另一个协程的子协程),前者这类构建器异常发生时会第一时间被抛出,而后者则依赖用户来最终消费异常,例如通过调用await或receive
  • 非根协程产生的异常总是被传播
异常传播的特性

当一个协程由于一个异常而运行失败时,它会传播这个异常并传递给它的父级。接下来父级会进行下面几步操作:

  • 取消它自己的子级协程
  • 取消它自己
  • 将异常传播并传递给它的父级
SupervisorJob和SupervisorScope
  • 使用SupervisorJob时,一个子协程的运行失败不会影响其他的子协程,SupervisorJob不会传播异常给它的父级,它会让子协程自己处理异常
  • 或者SupervisorScope中的子协程,一个失败,其他的子协程也不会受影响,但如果是协程作用域里面有异常失败,则所有子协程都会失败退出
异常的捕获
  • 使用CoroutineExceptionHandler对协程的异常进行捕获
  • 时机:异常是被自动抛出异常的协程抛出的(使用launch,而不是async时)
  • 位置:在CoroutineScope的CoroutineContext中或在一个根协程中(CoroutineScope或者supervisorScope的直接子协程)中
  • handler要安装在外部协程中,不能在内部协程中,否则捕获不到异常
@Test
fun `test exception handler`() = runBlocking {
    val coroutineExceptionHandler = CoroutineExceptionHandler { _, throwable ->
        println("handle exception: $throwable")
    }
    val scope = CoroutineScope(Job())
    //能捕获到异常
    val job1 = scope.launch(coroutineExceptionHandler) {
        launch { 
            throw IllegalArgumentException()
        }
    }
    val job2 = scope.launch() {
        //不能捕获到异常
        launch(coroutineExceptionHandler) { 
            throw IllegalArgumentException()
        }
    }
}
Android中全局异常处理
  • 全局异常处理器可以获取到所有协程未处理的未捕获异常,不过它不能对异常进行捕获。虽然不能阻止程序奔溃,全局异常处理器在程序调试和异常上报等场景中仍然有非常大的用处
  • 我们需要在classpath下面创建META-INF/services目录,并在其中创建一个名为kontlinx.coroutines.CoroutineExceptionHandler的文件,文件内容就是我们的全局异常处理器的全类名
class GlobeCoroutineExceptionHandler : CoroutineExceptionHandler {
    override val key = CoroutineExceptionHandler
    override fun handleException(context: CoroutineContext, exception: Throwable) {
        Log.d("xxx", "unHandle exception: $exception")
    }
}

然后再main目录下,新建resources/META-INF/services目录,然后新建kontlinx.coroutines.CoroutineExceptionHandler文件,内容为:

com.example.kotlincoroutine.GlobeCoroutineExceptionHandler
取消与异常处理
  • 取消与异常紧密相关,协程内部使用CancellationException来取消异常,但这个异常会被忽略
  • 当子协程被取消时,不会取消它的父协程
  • 如果一个协程遇到了CancellationException以外的异常,它将使用该异常取消它的父协程。当父协程的所有子协程都结束后,异常才会被父协程处理
//取消与异常
/*
* 打印顺序为:
* section 3
* section 1
* section 2
* handle exception:ArithmeticException
* 
* */
@Test
fun `test exception handler2`() = runBlocking {
    val handler = CoroutineExceptionHandler { _, throwable ->
        println("handle exception: $throwable")
    }
    val job = GlobalScope.launch(handler) {
        launch {
            try {
                delay(Long.MAX_VALUE)
            }finally {
                withContext(NonCancellable){
                    println("section 1")
                    delay(100)
                    println("section 2")
                }
            }
        }
        launch {
            delay(10)
            println("section 3")
            throw ArithmeticException()
        }
    }
    job.join()
}
异常的聚合
  • 当协程的多个子协程因为异常而失败时,一般情况下取第一个异常进行处理。在第一个异常之后发生的所有其他异常,都将被绑定到第一个异常之上。
  • 其他异常信息可以通过exception.suppressed.contentToString来打印出来

欢迎关注我的公众号,和我一起每天进步一点点!
这里写图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/613447.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一文讲透亚马逊云三层架构

关于三层架构,我们有很多想说的话: (以下内容以下都在VPC中) cloudfront做CDN加速网关规划S3做静态网站托管APIGateway作为统一网关入口认证/限流Lambda 作为传统后端,并发,底层架构Redis缓存DDB作为持久化…

Excel 根据分类及组内序号进行编码

例题描述和简单分析 Excel 记录课程数据,未排序,部分如下: ABC1CourseDateTime2Word1-Sep-209:003Word1-Sep-209:004PowerPoint1-Sep-209:005Word1-Sep-2012:006PowerPoint1-Sep-2012:007Excel1-Sep-2012:008Word1-Sep-2012:00 现在要新增…

发布一个属于自己的 npm工具包

我们可以发布一个属于自己的工具包到 npm 服务上,方便自己和其他开发者使用,参与社区贡献,操作步骤如下: 创建与发布 npm 初始化工具包,package.json 填写包的信息 (包的名字是唯一的)注册账号 https://www.npmjs.co…

13.跳跃游戏

文章目录 题目简介题目解答解法一:贪心算法+动态规划代码:复杂度分析: 题目链接 大家好,我是晓星航。今天为大家带来的是 跳跃游戏面试题 相关的讲解!😀 题目简介 题目解答 思路:这…

Django开发实战之定制管理后台界面及知识梳理(中)

上一篇文章末尾讲到如何能够展示更多的字段在界面上,那么针对整个界面数据,如果我想按照某一个条件进行筛选,我该怎么做呢,只需要加上下面一行代码 注意:中途只有代码片段,文末有今天涉及的所有代码 1、增…

RabbitMQ高级(MQ的问题,消息可靠性,死信交换机,惰性队列,MQ集群)【详解】

目录 一、MQ的问题 1. 问题说明 2. 准备代码环境 1 创建project 2 创建生产者模块 3 创建消费者模块 二、消息可靠性 1. 介绍 2. 生产者确认机制 3. MQ消息持久化 4. 消费者确认机制 5. 消费者auto模式的失败重试 6. 小结 三、死信交换机和延迟消息 1. 介绍 2. …

【前端部署】Ubuntu22.04 使用nginx部署vue前端项目教程

一.ubuntu安装nginx 1.更新本地软件包列表 sudo apt update2.安装nginx sudo apt install nginx3.验证nginx是否安装成功 sudo systemctl status nginx如果Nginx正在运行,则命令输出应该显示Active(active (running))状态。 4.若nginx未运…

【MySQL】——课程平台的创建设计

💻博主现有专栏: C51单片机(STC89C516),c语言,c,离散数学,算法设计与分析,数据结构,Python,Java基础,MySQL,linux&#xf…

2024HW Linux应急响应基础学习

首先展示关于Linux的关键目录,这是应急响应查看的关键: 常用命令 top //查看进程资源的占用情况 ps -aux //查看进程 直接写ps aux也可以 netstat -antpl //查看网络连接 ls -alh /proc/pid //查看某个pid对应的可执行程序 pid记得修改 lsof /…

微信登录功能--网站应用

微信开发平台注册https://open.weixin.qq.com/ 账号中心-填写基本资料(最好是公司注册) 账号中心-开发者资质认证(充钱,300) 审核通过之后,管理中心-网站应用-创建网站应用(AppSecret一定一定…

SMART700西门子触摸屏维修6AV6 648-0CC11-3AX0

西门子工控机触摸屏维修系列型号:PС477,PC677,TD200,TD400,KTP178,TP170A,TP170B,TP177A,TP177B,TP270,TP277,TP27,MP370,MP277,OP27,OP177B等。 触摸屏故障有:上电黑屏, 花屏,暗屏,触摸失灵,按键损坏,电源板,高压板故障,液晶,主板坏等,内容错乱、进不了…

nacos server安装部署傻瓜级教程

下载地址:GitHub - alibaba/nacos: an easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications.an easy-to-use dynamic service discovery, configuration and service management platfo…

C++ 搜索二叉树

目录 1.二叉搜索树概念 2. 实现二叉搜索树 2.1. 二叉搜索树的插入 2.2查找 2.3删除节点 3.二叉树的应用(KV结构) 1.二叉搜索树概念 二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树: 若它的左子树不为…

AutoCAD中密集的填充打散后消失的问题

有时候在AutoCAD中,图案填充的填充面积过大或填充太过密集时,将该填充打散,也就是执行Explode时,会发现填充图案消失了。 原因是打散后线条太大,系统就不显示了。可以通过设置:HPMAXLINES 值,来…

奇诡 matlab 小 bug matlab git需要记录的改动太多

似乎是我有一次添加了太多的路径之后的事情。但是不敢说一定是这个导致的: 症状:只要对文本进行任何编辑操作,工作区就会出现"Processing … Cancel"的提示,如果不管的话这个提示不会消失,同时matlab变得越来…

Minimal-Supervised Medical Image Segmentation via Vector Quantization Memory

文章目录 Minimal-Supervised Medical Image Segmentation via Vector Quantization Memory摘要方法实验结果 Minimal-Supervised Medical Image Segmentation via Vector Quantization Memory 摘要 辅助重构分支:该分支通过提供额外的监督并产生学习视觉表示所需…

2025COSP深圳户外展已定档招商工作正式启动!抢占先机,领跑华南市场

想开拓全国最具消费能力的华南市场? 想招到优质的实力经销商? 想快速的提高品牌知名度? 2025-COSP深圳国际户外展会将于2025年2月27-3月1日在深圳福田会展中心盛大开幕! 回顾过去 2024-COSP深圳国际户外展我们取得了较好的成绩…

UEC++ FString做为参数取值时报错error:C4840

问题描述 用来取FString类型的变量时报错: 问题解决 点击错误位置,跳转到代码: void AMyDelegateActor::TwoParamDelegateFunc(int32 param1, FString param2) {UE_LOG(LogTemp, Warning, TEXT("Two Param1:%d Param2:%s"), param…

流量分析(一)

数据库类流量分析 MySQL流量 常规操作,查找flag ctfhub{} 注意要选择字符集 Redis流量 查找ctfhub结果没找到 尝试把其变成十六进制继续进行查找 看到了前半段flag 接着往下看 找到了后半段的flag MongoDB流量 还是一样查找ctfhub 字符串没找到 转成十六进制也没…

【算法】二叉树中的dfs

快乐的流畅:个人主页 个人专栏:《算法神殿》《数据结构世界》《进击的C》 远方有一堆篝火,在为久候之人燃烧! 文章目录 引言一、计算布尔二叉树的值二、求根节点到叶节点数字之和三、二叉树剪枝四、验证搜索二叉树五、二叉搜索树中…