
我们使用构建器Launch去启动协程的时候,都需要指定协程上下文(没有显示指定会使用默认值)。
协程上下文(CoroutineContext)是一组用于定义协程的行为元素。它由如下几项构成
job(控制协程的生命周期),CoroutineDispatcher(向合适的线程发任务),CoroutineName(协程的名称,调用的时候很有用),CoroutineExceptionHandler(处理未被捕获的异常)
1,协程上下文的继承
对于新创建的线程,它的CoroutineCoroutineContexttContext包含了一个全新的job实例。它会帮助我们控制协程的生命周期。而剩下的元素会从CoroutineContext的父类继承,该父类可能是另外一个协程,或者创建协程的CoroutineScope。
package com.example.testkotlin1030
import kotlinx.coroutines.*
import org.junit.Test
import org.junit.Assert.*
import kotlin.coroutines.CoroutineContext
import kotlin.system.measureTimeMillis
class ExampleUnitTest {
@Test
fun `my test`() = runBlocking {//必须指定泛型类型为,不然报错
//创建一个协程作用域,需要指定协程上下文
//有时候需要在协程上下文中定义多个元素,我们可以使用+ *** 作符来实现
val scope = CoroutineScope(Job()+Dispatchers.IO+CoroutineName("test"))
val job = scope.launch {
//打印出launch启动的协程的Job对象,
println("1111111${coroutineContext[Job]} ${Thread.currentThread().name}")
val result = async {//launch的子协程
println("22222222${coroutineContext[Job]} ${Thread.currentThread().name}")
"OK"
}.await()
}
job.join()
}
}
打印输出
1111111"test#2":StandaloneCoroutine{Active}@3b1ca9c4 DefaultDispatcher-worker-1 @test#2
22222222"test#3":DeferredCoroutine{Active}@40608051 DefaultDispatcher-worker-3 @test#3
Job对象不一样,是一个全新的实例,其它的从父类继承。打印线程的时候自动会把协程的名字打印出来
2,协程上下文的继承公式
package com.example.testkotlin1030
import kotlinx.coroutines.*
import org.junit.Test
import org.junit.Assert.*
import kotlin.coroutines.CoroutineContext
import kotlin.system.measureTimeMillis
class ExampleUnitTest {
@Test
fun `my test`() = runBlocking {
val exceptionHandler = CoroutineExceptionHandler { _, exception ->
println("caught $exception")//其实是回掉函数
}
val scope = CoroutineScope(Job() + Dispatchers.Main+exceptionHandler)
val job = scope.launch(Dispatchers.IO) {
}
}
}
协程的异常处理
代码理解
package com.example.testkotlin1030
import kotlinx.coroutines.*
import org.junit.Test
import org.junit.Assert.*
import java.lang.ArithmeticException
import java.lang.IndexOutOfBoundsException
import kotlin.coroutines.CoroutineContext
import kotlin.system.measureTimeMillis
class ExampleUnitTest {
@Test
fun `my test`() = runBlocking {
val job1 = GlobalScope.launch {
throw IndexOutOfBoundsException()
}
job1.join()
val job2 = GlobalScope.async {
throw ArithmeticException()
}
job2.await()
}
}
这里会抛出两个异常,注意这两个异常的catch地方不一样
package com.example.testkotlin1030
import kotlinx.coroutines.*
import org.junit.Test
import org.junit.Assert.*
import java.lang.ArithmeticException
import java.lang.Exception
import java.lang.IndexOutOfBoundsException
import kotlin.coroutines.CoroutineContext
import kotlin.system.measureTimeMillis
class ExampleUnitTest {
@Test
fun `my test`() = runBlocking {
val job1 = GlobalScope.launch {
try {
throw IndexOutOfBoundsException()
} catch (e: Exception) {
e.printStackTrace()
}
}
job1.join()
val job2 = GlobalScope.async {
throw ArithmeticException()
}
try {
job2.await()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
非根协程所创建的协程中,产生的异常总会是被传播
package com.example.testkotlin1030
import kotlinx.coroutines.*
import org.junit.Test
import org.junit.Assert.*
import java.lang.ArithmeticException
import java.lang.Exception
import java.lang.IllegalArgumentException
import java.lang.IndexOutOfBoundsException
import kotlin.coroutines.CoroutineContext
import kotlin.system.measureTimeMillis
class ExampleUnitTest {
@Test
fun `my test`() = runBlocking {
val scope = CoroutineScope(Job())
val job = scope.launch {
async {
//如果async抛出异常,launch就会立即抛出异常,而不会调用.await()
throw IllegalArgumentException()
}
}
job.join()
}
}
一个child失败了,其它的child也取消了。
代码体会第一点
package com.example.testkotlin1030
import kotlinx.coroutines.*
import org.junit.Test
import org.junit.Assert.*
import java.lang.ArithmeticException
import java.lang.Exception
import java.lang.IllegalArgumentException
import java.lang.IndexOutOfBoundsException
import kotlin.coroutines.CoroutineContext
import kotlin.system.measureTimeMillis
class ExampleUnitTest {
@Test
fun `my test`() = runBlocking {
val supervisor = CoroutineScope(SupervisorJob())
//job1泡了异常,job2还会执行
val job1 = supervisor.launch {
delay(100)
println("111111111111111")
throw IllegalArgumentException()
}
val job2 = supervisor.launch {
try {
delay(1000)
}finally {
println("2222222222222")
}
}
joinAll(job1,job2)
}
}
打印输出
111111111111111 Exception in thread "DefaultDispatcher-worker-1 @coroutine#2" java.lang.IllegalArgumentException at com.example.testkotlin1030.ExampleUnitTest$my test$job1.invokeSuspend(ExampleUnitTest.kt:27) 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) 2222222222222
package com.example.testkotlin1030
import kotlinx.coroutines.*
import org.junit.Test
import org.junit.Assert.*
import java.lang.ArithmeticException
import java.lang.AssertionError
import java.lang.Exception
import java.lang.IllegalArgumentException
import java.lang.IndexOutOfBoundsException
import kotlin.coroutines.CoroutineContext
import kotlin.system.measureTimeMillis
class ExampleUnitTest {
@Test
fun `my test`() = runBlocking {
val handler = CoroutineExceptionHandler{_,exception ->
println("caught $exception")
}
val job = GlobalScope.launch (handler){
throw AssertionError()//该异常会被捕获
}
val deferred = GlobalScope.async (handler){
throw ArithmeticException()
}
job.join()
deferred.await()
}
}
异常捕获的错误写法
package com.example.testkotlin1030
import kotlinx.coroutines.*
import org.junit.Test
import org.junit.Assert.*
import java.lang.ArithmeticException
import java.lang.AssertionError
import java.lang.Exception
import java.lang.IllegalArgumentException
import java.lang.IndexOutOfBoundsException
import kotlin.coroutines.CoroutineContext
import kotlin.system.measureTimeMillis
class ExampleUnitTest {
@Test
fun `my test`() = runBlocking {
val handler = CoroutineExceptionHandler{_,exception ->
println("caught $exception")
}
val scope = CoroutineScope(Job())
val job = scope.launch {
launch (handler){
throw AssertionError()
}
}
job.join()
}
}
正确的写法应该是
package com.example.testkotlin1030
import kotlinx.coroutines.*
import org.junit.Test
import org.junit.Assert.*
import java.lang.ArithmeticException
import java.lang.AssertionError
import java.lang.Exception
import java.lang.IllegalArgumentException
import java.lang.IndexOutOfBoundsException
import kotlin.coroutines.CoroutineContext
import kotlin.system.measureTimeMillis
class ExampleUnitTest {
@Test
fun `my test`() = runBlocking {
val handler = CoroutineExceptionHandler { _, exception ->
println("caught $exception")
}
val scope = CoroutineScope(Job())
val job = scope.launch(handler) {
launch {
throw AssertionError()
}
}
job.join()
}
}
异常处理器不能安装在内部协程,应该安装在外部协程
android 中捕获异常阻止程序闪退
package com.dongnaoedu.kotlincoroutineexception
import android.os.Bundle
import android.util.Log
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val handler = CoroutineExceptionHandler { _, exception ->
Log.d("ning", "Caught $exception")
}
findViewById
package com.dongnaoedu.kotlincoroutineexception
import android.util.Log
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlin.coroutines.CoroutineContext
class GlobalCoroutineExceptionHandler : CoroutineExceptionHandler {
override val key = CoroutineExceptionHandler
override fun handleException(context: CoroutineContext, exception: Throwable) {
Log.d("ning","Unhandled Coroutine Exception: $exception")//依然会崩溃
}
}
取消与异常紧密相关,协程内部使用CancellationException来进行取消,这个异常会被忽略
当子协程被取消时,不会取消它的父协程
@Test
fun `test cancel and exception`() = runBlocking {
val job = launch {
val child = launch {
try {
delay(Long.MAX_VALUE)
} finally {
println("Child is cancelled.")
}
}
yield()
println("Cancelling child")
child.cancelAndJoin()
yield()
println("Parent is not cancelled")
}
job.join()
}
打印输出
Cancelling child
Child is cancelled.
Parent is not cancelled
//如果一个协程遇到了CancellationException以外的异常,它将使用该异常取消它的父协程。当
//父协程的所有子协程都结束后,异常才会被父协程处理。
@Test
fun `test cancel and exception2`() = runBlocking {
val handler = CoroutineExceptionHandler { _, exception ->
println("Caught $exception")
}
val job = GlobalScope.launch(handler) {
launch {
try {
delay(Long.MAX_VALUE)
} finally {
withContext(NonCancellable) {
println("Children are cancelled, but exception is not handled until all children terminate")
delay(100)
println("The first child finished its non cancellable block")
}
}
}
launch {
delay(10)
println("Second child throws an exception")
throw ArithmeticException()
}
}
job.join()
}
//如果一个协程遇到了CancellationException以外的异常,它将使用该异常取消它的父协程。当
//父协程的所有子协程都结束后,异常才会被父协程处理。
@Test
fun `test cancel and exception2`() = runBlocking {
val handler = CoroutineExceptionHandler { _, exception ->
println("Caught $exception")
}
val job = GlobalScope.launch(handler) {
launch {
try {
delay(Long.MAX_VALUE)
} finally {
withContext(NonCancellable) {
println("Children are cancelled, but exception is not handled until all children terminate")
delay(100)
println("The first child finished its non cancellable block")
}
}
}
launch {
delay(10)
println("Second child throws an exception")
throw ArithmeticException()
}
}
job.join()
}
打印输出:
Second child throws an exception
Children are cancelled, but exception is not handled until all children terminate
The first child finished its non cancellable block
Caught java.lang.ArithmeticException
@Test
fun `test exception aggregation`() = runBlocking {
val handler = CoroutineExceptionHandler { _, exception ->
println("Caught $exception ${exception.suppressed.contentToString()}")
}
val job = GlobalScope.launch(handler) {
launch {
try {
delay(Long.MAX_VALUE)
} finally {
throw ArithmeticException() //2
}
}
launch {
try {
delay(Long.MAX_VALUE)
} finally {
throw IndexOutOfBoundsException() //3
}
}
launch {
delay(100)
throw IOException() //1
}
}
job.join()
}
}
打印输出
Caught java.io.IOException [java.lang.IndexOutOfBoundsException, java.lang.ArithmeticException]
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)