| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 移动开发 -> 史上最详Android版kotlin协程入门进阶实战(三),头条android面试节奏 -> 正文阅读 |
|
[移动开发]史上最详Android版kotlin协程入门进阶实战(三),头条android面试节奏 |
//省略… internal inner class Worker private constructor() : Thread() { override fun run() = runWorker() private fun runWorker() { var rescanned = false while (!isTerminated && state != WorkerState.TERMINATED) { val task = findTask(mayHaveLocalTasks) if (task != null) { rescanned = false minDelayUntilStealableTaskNs = 0L executeTask(task) continue } else { mayHaveLocalTasks = false } //省略… continue } } private fun executeTask(task: Task) { //省略… runSafely(task) //省略… } fun findTask(scanLocalQueue: Boolean): Task? { if (tryAcquireCpuPermit()) return findAnyTask(scanLocalQueue) val task = if (scanLocalQueue) { localQueue.poll() ?: globalBlockingQueue.removeFirstOrNull() } else { globalBlockingQueue.removeFirstOrNull() } return task ?: trySteal(blockingOnly = true) } //省略… } //省略… } 哎呀呀,不得了,跟我们上面想的一模一样。 很明显并没有,我们看到 继续往下分析,我们看看这个 internal class GlobalQueue : LockFreeTaskQueue(singleConsumer = false) internal actual typealias SchedulerTask = Task 我可以看到这个队列里面存放的就是 internal abstract class DispatchedTask( @JvmField public var resumeMode: Int ) : SchedulerTask() { //省略… internal open fun getExceptionalResult(state: Any?): Throwable? = (state as? CompletedExceptionally)?.cause public final override fun run() { assert { resumeMode != MODE_UNINITIALIZED } val taskContext = this.taskContext var fatalException: Throwable? = null try { val delegate = delegate as DispatchedContinuation val continuation = delegate.continuation withContinuationContext(continuation, delegate.countOrElement) { val context = continuation.context val state = takeState() val exception = getExceptionalResult(state) val job = if (exception == null && resumeMode.isCancellableMode) context[Job] else null if (job != null && !job.isActive) { val cause = job.getCancellationException() cancelCompletedResult(state, cause) continuation.resumeWithStackTrace(cause) } else { if (exception != null) { continuation.resumeWithException(exception) } else { continuation.resume(getSuccessfulResult(state)) } } } } catch (e: Throwable) { fatalException = e } finally { val result = runCatching { taskContext.afterTask() } handleFatalException(fatalException, result.exceptionOrNull()) } } } 接着我们继续看 public inline fun Continuation.resumeWithException(exception: Throwable): Unit = resumeWith(Result.failure(exception)) 诶,不对啊,我们在这里还没有执行 是滴,这里只是一种可能,我们现在回到调用 val delegate = delegate as DispatchedContinuation val continuation = delegate.continuation internal abstract class BaseContinuationImpl( public val completion: Continuation<Any?>? ) : Continuation<Any?>, CoroutineStackFrame, Serializable { public final override fun resumeWith(result: Result<Any?>) { var current = this var param = result while (true) { probeCoroutineResumed(current) with(current) { val completion = completion!! // fail fast when trying to resume continuation val outcome: Result<Any?> = try { val outcome = invokeSuspend(param) if (outcome === COROUTINE_SUSPENDED) return Result.success(outcome) } catch (exception: Throwable) { Result.failure(exception) } releaseIntercepted() // this state machine instance is terminating if (completion is BaseContinuationImpl) { current = completion param = outcome } else { completion.resumeWith(outcome) return } } } } } 可以看到最终这里面 那、那、那、那下面那个
public interface ThreadContextElement public fun updateThreadContext(context: CoroutineContext): S public fun restoreThreadContext(context: CoroutineContext, oldState: S) } 我们看到 public fun handleFatalException(exception: Throwable?, finallyException: Throwable?) { //省略… handleCoroutineException(this.delegate.context, reason) } public fun handleCoroutineException(context: CoroutineContext, exception: Throwable) { try { context[CoroutineExceptionHandler]?.let { it.handleException(context, exception) return } } catch (t: Throwable) { handleCoroutineExceptionImpl(context, handlerException(exception, t)) return } handleCoroutineExceptionImpl(context, exception) } 我们看到 internal actual fun handleCoroutineExceptionImpl(context: CoroutineContext, exception: Throwable) { for (handler in handlers) { try { handler.handleException(context, exception) } catch (t: Throwable) { val currentThread = Thread.currentThread() currentThread.uncaughtExceptionHandler.uncaughtException(currentThread, handlerException(exception, t)) } } val currentThread = Thread.currentThread() currentThread.uncaughtExceptionHandler.uncaughtException(currentThread, exception) } 不知道各位是否理解了上面的流程,笔者最开始的时候也是被这里来来回回的。绕着晕乎乎的。如果没看懂的话,可以休息一下,揉揉眼睛,倒杯热水,再回过头捋一捋。 好滴,到此处为止。我们已经大概的了解kotlin协程中异常是如何抛出的,下面我们就不再不过多延伸。下面我们来说说异常的处理。 kotlin协程异常处理我们要分成两部分来看,通过上面的分解我们知道一种异常是通过 第一种:当然就是我们最常用的 private fun testException(){ GlobalScope.launch{ launch(start = CoroutineStart.UNDISPATCHED) { Log.d("${Thread.currentThread().name}", " 我要开始抛异常了") try { throw NullPointerException(“异常测试”) } catch (e: Exception) { e.printStackTrace() } } Log.d("${Thread.currentThread().name}", “end”) } } D/DefaultDispatcher-worker-1: 我要开始抛异常了 W/System.err: java.lang.NullPointerException: 异常测试 W/System.err: at com.carman.kotlin.coroutine.MainActivity$testException$1$1.invokeSuspend(MainActivity.kt:252) W/System.err: at com.carman.kotlin.coroutine.MainActivity$testException$1$1.invoke(Unknown //省略… D/DefaultDispatcher-worker-1: end 诶嘿,这个时候我们程序没有崩溃,只是输出了警告日志而已。那如果遇到 private fun testException(){ var a:MutableList = mutableListOf(1,2,3) GlobalScope.launch{ launch { Log.d("${Thread.currentThread().name}",“我要开始抛异常了” ) try { launch{ Log.d(" T h r e a d . c u r r e n t T h r e a d ( ) . n a m e " , " {Thread.currentThread().name}", " Thread.currentThread().name","{a[1]}") } a.clear() } catch (e: Exception) { e.printStackTrace() } } Log.d("${Thread.currentThread().name}", “end”) } } D/DefaultDispatcher-worker-1: end D/DefaultDispatcher-worker-2: 我要开始抛异常了 E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-2 Process: com.carman.kotlin.coroutine, PID: 5394 java.lang.IndexOutOfBoundsException: Index: 1, Size: 0 at java.util.ArrayList.get(ArrayList.java:437) at com.carman.kotlin.coroutine.MainActivity$testException$1$1$1.invokeSuspend(MainActivity.kt:252) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106) at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665) 当你以为使用 是,当然没问题。但是你能保证你每次都能记住吗,你的同一战壕里的战友会记住吗。而且当你的逻辑比较复杂的时候,你使用那么多 这个时候就需要使用协程上下文中的 public interface CoroutineExceptionHandler : CoroutineContext.Element { public companion object Key : CoroutineContext.Key public fun handleException(context: CoroutineContext, exception: Throwable) } 我们稍作修改: private fun testException(){ val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable -> Log.d(“exceptionHandler”, “ c o r o u t i n e C o n t e x t [ C o r o u t i n e N a m e ] : {coroutineContext[CoroutineName]} : coroutineContext[CoroutineName]:throwable”) } GlobalScope.launch(CoroutineName(“异常处理”) + exceptionHandler){ val job = launch{ Log.d("${Thread.currentThread().name}",“我要开始抛异常了” ) throw NullPointerException(“异常测试”) } Log.d("${Thread.currentThread().name}", “end”) } } D/DefaultDispatcher-worker-1: 我要开始抛异常了 D/exceptionHandler: CoroutineName(异常处理) :java.lang.NullPointerException: 异常测试 D/DefaultDispatcher-worker-2: end 这个时候即使我们没有使用
我们之前在讲到
默认情况下,当协程因出现异常失败时,它会将异常传播到它的父级,父级会取消其余的子协程,同时取消自身的执行。最后将异常在传播给它的父级。当异常到达当前层次结构的根,在当前协程作用域启动的所有协程都将被取消。 我们在前一个案例的基础上稍作做一下修改,只在父协程上添加 private fun testException(){ val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable -> Log.d(“exceptionHandler”, “ c o r o u t i n e C o n t e x t [ C o r o u t i n e N a m e ] 处 理 异 常 : {coroutineContext[CoroutineName]} 处理异常 : coroutineContext[CoroutineName]处理异常:throwable”) } GlobalScope.launch(CoroutineName(“父协程”) + exceptionHandler){ val job = launch(CoroutineName(“子协程”)) { Log.d("${Thread.currentThread().name}",“我要开始抛异常了” ) for (index in 0…10){ launch(CoroutineName(“孙子协 Log.d(" T h r e a d . c u r r e n t T h r e a d ( ) . n a m e " , " {Thread.currentThread().name}"," Thread.currentThread().name","{coroutineContext[CoroutineName]}" ) } } throw NullPointerException(“空指针异常”) } for (index in 0…10){ launch(CoroutineName(“子协程$index”)) { Log.d(" T h r e a d . c u r r e n t T h r e a d ( ) . n a m e " , " {Thread.currentThread().name}"," Thread.currentThread().name","{coroutineContext[CoroutineName]}" ) } } try { job.join() } catch (e: Exception) { e.printStackTrace() } Log.d("${Thread.currentThread().name}", “end”) } } D/DefaultDispatcher-worker-3: 我要开始抛异常了 W/System.err: kotlinx.coroutines.JobCancellationException: StandaloneCoroutine is cancelling; job=StandaloneCoroutine{Cancelling}@f6b7807 W/System.err: Caused by: java.lang.NullPointerException: 空指针异常 W/System.err: at com.carman.kotlin.coroutine.MainActivity$testException 1 1 1job$1.invokeSuspend(MainActivity.kt:26//省略… D/DefaultDispatcher-worker-6: end D/exceptionHandler: CoroutineName(父协程) 处理异常 :java.lang.NullPointerException: 空指针异常 我们看到子协程 如果有一个页面,它最终展示的数据,是通过请求多个服务器接口的数据拼接而成的,而其中某一个接口出问题都将不进行数据展示,而是提示加载失败。那么你就可以使用上面的方案去做,都不用管它们是谁报的错,反正都是统一处理,一劳永逸。类似这样的例子我们在开发中应该经常遇到。 但是另外一个问题就来了。例如我们APP的首页,首页上展示的数据五花八门。如:广告,弹窗,未读状态,列表数据等等都在首页存在,但是他们相互之间互不干扰又不关联,即使其中某一个失败了也不影响其他数据展示。那通过上面的方案,我们就没办法处理。 这个时候我们就可以通过 我们在讲解 /**
*/ public suspend fun supervisorScope(block: suspend CoroutineScope.() -> R): R { //省略… } 这段是摘自官方文档的,其他的我把它们省略了,只留了一句:“ private fun testException(){ val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable -> Log.d(“exceptionHandler”, “ c o r o u t i n e C o n t e x t [ C o r o u t i n e N a m e ] . t o S t r i n g ( ) 处 理 异 常 : {coroutineContext[CoroutineName].toString()} 处理异常 : coroutineContext[CoroutineName].toString()处理异常:throwable”) } GlobalScope.launch(exceptionHandler) { supervisorScope { launch(CoroutineName(“异常子协程”)) { Log.d("${Thread.currentThread().name}", “我要开始抛异常了”) throw NullPointerException(“空指针异常”) /**
*/ public suspend fun supervisorScope(block: suspend CoroutineScope.() -> R): R { //省略… } 这段是摘自官方文档的,其他的我把它们省略了,只留了一句:“ private fun testException(){ val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable -> Log.d(“exceptionHandler”, “ c o r o u t i n e C o n t e x t [ C o r o u t i n e N a m e ] . t o S t r i n g ( ) 处 理 异 常 : {coroutineContext[CoroutineName].toString()} 处理异常 : coroutineContext[CoroutineName].toString()处理异常:throwable”) } GlobalScope.launch(exceptionHandler) { supervisorScope { launch(CoroutineName(“异常子协程”)) { Log.d("${Thread.currentThread().name}", “我要开始抛异常了”) throw NullPointerException(“空指针异常”) |
|
移动开发 最新文章 |
Vue3装载axios和element-ui |
android adb cmd |
【xcode】Xcode常用快捷键与技巧 |
Android开发中的线程池使用 |
Java 和 Android 的 Base64 |
Android 测试文字编码格式 |
微信小程序支付 |
安卓权限记录 |
知乎之自动养号 |
【Android Jetpack】DataStore |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
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/24 13:00:37- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |