当前位置:网站首页>Kotlin collaboration -- context and exception handling
Kotlin collaboration -- context and exception handling
2022-06-13 06:26:00 【m0_ forty-seven million nine hundred and fourteen thousand one 】
One . Collaboration context
1. The composition of the context of the collaboration
CoroutineContext Is a set of elements that define the behavior of a coroutine . It consists of the following .
Job: Control the lifecycle of the process
CoroutineDispatcher: Distribute tasks to the appropriate threads
CoroutineName: The name of the program , It's useful when debugging
CoroutineExceptionHandler: Handling uncapped exceptions
2. Combine elements in context
@Test
fun testCoroutineContext() = runBlocking {
// Here, the scheduler and CoroutineName Operator addition
launch(Dispatchers.Default + CoroutineName("test")) {
println("I'm working in thread ${Thread.currentThread().name}")
}
}Print the results :
I'm working in thread DefaultDispatcher-worker-1 @test#2Eat the name after the printout @test#2 Need to be in test Folder , Progressive unit testing will occur .
3. Inheritance of coroutine context
For the newly created collaboration , its CoroutineContext Will include a new J0b example , It will help us to control the lifecycle of the coprocessor . and The rest of the elements will The elements of CoroutineContext Inherits from the parent class of , The parent class may be another coroutine or the one that created it CoroutineScope.
@Test
fun testCoroutineContextExtend() = runBlocking {
var scope = CoroutineScope(Job() + Dispatchers.IO + CoroutineName("testExtend"))
val launch = scope.launch {
//launch by scope It's the son of Xie Cheng , Will inherit scope The context of
println("${coroutineContext[Job]} ${Thread.currentThread().name}")
val async = async {
//async by launch It's the son of Xie Cheng , Will inherit scope The context of
println("${coroutineContext[Job]} ${Thread.currentThread().name}")
"OK"
}.await()
}
launch.join()
}Print the results :
"testExtend#2":StandaloneCoroutine{Active}@6318c9c9 DefaultDispatcher-worker-1 @testExtend#2
"testExtend#3":DeferredCoroutine{Active}@11fd5300 DefaultDispatcher-worker-3 @testExtend#3The difference is because , Every Job The objects are all different .
The context of the coroutine = The default value is + inherited CoroutineContext+ Parameters
Some elements contain default values :Dispatchers.DefauIt By default CoroutineDispatcher, as well as “coroutine"
By default CoroutineName;
inherited CoroutineContext yes CoroutineScope Or his father's CoroutineContext;
Parameters passed into the collaboration builder take precedence over inherited context parameters , Therefore, the corresponding parameter value will be overridden .
@Test
fun testCoroutineContextExtend2() = runBlocking {
val coroutineExceptionHandler = CoroutineExceptionHandler { _, exception ->
println("Caught:$exception")
}
val coroutineScope = CoroutineScope(
Job() + Dispatchers.Main + coroutineExceptionHandler
)
// If the collaboration built through the parent scope is not redefined, it will directly inherit the parameters of the parent class , If you define yourself, you will use your own
// I've said before job The object of is different every time
coroutineScope.launch(Dispatchers.IO) {
}
}Two . Exception handling of coroutine
1. Exception handling of root coroutine
There are two forms of coprocessor : Auto propagate exception (launch And actor), Expose exceptions to users (async And produce) When these builders are used to create a Root co process time ( This process is not a child of another process ), The former type of builder , An exception is thrown the first time it occurs , The latter relies on users to end up with abnormal consumption , For example, through await or receive.
// Root process abnormality
fun testExceptionPropagation() = runBlocking<Unit> {
// Auto propagate exception
//launch It was thrown abnormally
val launch = GlobalScope.launch {
try {
throw IndexOutOfBoundsException() // This line throws
} catch (e: Exception) {
println("Caught IndexOutOfBoundsException")
}
}
launch.join()
// Propagate exceptions to users
//async It was thrown abnormally
val async = GlobalScope.async {
throw ArrayIndexOutOfBoundsException()
}
try {
//async This exception will not be triggered when it is not started catch To
async.await() // This line throws
} catch (e: Exception) {
println("Caught ArrayIndexOutOfBoundsException")
}
}Print the results :
Caught IndexOutOfBoundsException
Caught ArrayIndexOutOfBoundsExceptionThis is illustrated by the above code ,launch The abnormal normal of can catch To ,async The exception of must be called await When the method is used catch
2. Non root coroutine exception handling
// Non root coroutine exception Of async An exception will be thrown immediately
fun testExceptionPropagation2() = runBlocking<Unit> {
val coroutineScope = CoroutineScope(Job())
val launch = coroutineScope.launch {
async {
throw IndexOutOfBoundsException()
}
}
launch.join()
}This code will report an error as soon as it runs , here async If an exception occurs as a child process, it will be uploaded to the , and launch If the exception cannot be handled, an error will be reported .
3. Abnormal propagation characteristics
When a coroutine fails due to an exception , He will propagate the exception and pass it to its parent , Next, the parent will perform the following operations :
1. Cancel his own rank
2. Cancel himself
3. Pass the exception to its parent
4.SupervisorJob
@Test
// Use SupervisorJob Problems in one subprocess will not affect other subprocesses
fun testSupervisorJob() = runBlocking<Unit> {
val coroutineScope = CoroutineScope(SupervisorJob())
val launch = coroutineScope.launch {
throw IndexOutOfBoundsException()
}
val launch1 = coroutineScope.launch {
delay(1000)
println(" No abnormality ")
}
//coroutineScope.cancel()// After the parent scope is canceled , The child threads inside will also be canceled
joinAll(launch, launch1)
}
}SupervisorJob The result is that one of the processes is abnormal , Other subprocesses will continue to execute .
5.supervisorScope
//supervisorScope When an exception occurs in the scope of ,supervisorScope It will all fail
fun testSupervisorScope() = runBlocking<Unit> {
supervisorScope {
//throw IndexOutOfBoundsException()
val launch = launch {
try {
print("child 1 finished.")
delay(Long.MAX_VALUE)
} finally {
print("child 2 finished.")
}
}
yield()
println("asdsadsafdsag")
throw ClassNotFoundException()
}
}6. Capture exception
1.CoroutineExceptionHandler
Use CoroutineExceptionHandler Catch the exception of the cooperation process .
When the following conditions are met , The exception will be caught :
opportunity : An exception is thrown by a coroutine that automatically throws an exception ( Use launch, instead of async when );
Location : stay CoroutineScope Of CoroutineContext Or in a root coroutine (CoroutineScope perhaps supe
rvisorScope Direct subprocess of ) in .
//launch Will automatically throw an exception, so you can catch Still in Scope In the process of building the root collaboration
fun testCoroutineExceptionHandler() = runBlocking<Unit> {
val coroutineExceptionHandler = CoroutineExceptionHandler { _, exception ->
println("Caught $exception")
}
val job = GlobalScope.launch(coroutineExceptionHandler) {
throw AssertionError() // Can capture
}
val async = GlobalScope.async(coroutineExceptionHandler) {
throw ArithmeticException();// You can't
}
job.join()
async.await()
}2. Global exception handling
The global exception handler can get all unhandled exceptions of the collaboration , However, it does not capture exceptions ,
Although not It can prevent the program from crashing , The global exception handler still has a very large capacity in scenarios such as program debugging and exception reporting
use .
We need to be in classpath Create below META-lNF/services Catalog , And create one of them called kot|inx.
coroutines.CoroutineExceptionHandler The file of , The contents of the file are our global exception handlers
Full class name of .
class GlobalCoroutineExceptionHandler:CoroutineExceptionHandler {
override val key= CoroutineExceptionHandler
override fun handleException(context: CoroutineContext, exception: Throwable) {
Log.d("ning","Unhandled Coroutine Exception: $exception")
}
}First create the exception capture class .

Then create kot|inx.coroutines.CoroutineExceptionHandler file
com.example.kotlincoroutineexception.GlobalCoroutineExceptionHandlerIt contains the full path of the exception capture class .
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.apply {
setOnClickListener {
GlobalScope.launch {
"abc".substring(10)
}
}
}
}Then you can catch it by reporting an error in the process .
Capture information :
Unhandled Coroutine Exception: java.lang.StringIndexOutOfBoundsException: length=3; index=103. Cancel and exception
1. Cancellation is closely related to exceptions , Used internally in the process CancellationException To cancel , This exception will be ignored .
2. When the subprocess is cancelled , It will not cancel its parent process .
fun testCancelAndException() = runBlocking<Unit> {
launch {
val child = launch {
try {
// Delay , Hang up
delay(Long.MAX_VALUE)
} finally {
println("Child is cancelled")
}
}
yield()
println("Cancelling child")
child.cancelAndJoin()
yield()
println("Parent is not cancelled.")
}
}Print the results :
Cancelling child
Child is cancelled
Parent is not cancelled.If a collaboration encounters CanceIIationException An exception , It will use this exception to cancel its parent coroutine . When all the child processes of the parent process are finished , Exceptions will be handled by the parent coroutine .
// If a collaboration encounters an exception other than cancellation , He will use the exception to cancel its parent 、 The parent process must close all the child processes to handle exceptions ( Throw out )
fun testCancelAndException2() = runBlocking<Unit> {
val handler = CoroutineExceptionHandler() { _, e ->
println("Caught $e")
}
val launch = GlobalScope.launch(handler) {
launch {
try {
// Delay , Hang up
delay(Long.MAX_VALUE)
} finally {
withContext(NonCancellable) {
println("Children are cancelled, but exception is not handled until all")
delay(100)
println("The first child finished its non cancellable block ")
}
}
}
launch {
delay(100)
println("Second child h")
}
}
launch.join()
}Print the results :
Second child h
Children are cancelled, but exception is not handled until all
The first child finished its non cancellable block
Caught java.lang.ArithmeticException4. Catch exceptions of all sub processes
When multiple child processes of a process fail due to exceptions , Generally, the first exception is taken for processing . All other exceptions that occur after the first exception , Will be Bind to the first exception .
// Check the exceptions of all sub processes
fun testExceptionAggregation() = runBlocking<Unit> {
val handler = CoroutineExceptionHandler() { _, e ->
println("Caught $e ${e.suppressed.contentToString()}")
}
val launch = GlobalScope.launch(handler) {
launch {
try {
delay(Long.MAX_VALUE)
} finally {
throw ArithmeticException();
}
}
launch {
try {
delay(Long.MAX_VALUE)
} finally {
throw IndexOutOfBoundsException();
}
}
launch {
throw IOException();
}
}
launch.join()
}Print the results :
Caught java.io.IOException [java.lang.ArithmeticException, java.lang.IndexOutOfBoundsException]边栏推荐
- 万能播放器 PotPlayer 的下载与安装,直播流 m3u8 导入
- Echart line chart: when multiple lines have the same name, the legend is still displayed
- Kotlin basic definition class, initialization and inheritance
- The jadx decompiler can decompile jars and apks
- Applet Use of spaces
- Uniapp mobile terminal uses canvas to draw background convex arc
- Waterfall flow layout of uni app Homepage
- [JS] array flattening
- Wechat applet uploads pictures (preview deletion limits the size and number of pictures)
- Dragon Boat Festival wellbeing, use blessing words to generate word cloud
猜你喜欢

二分查找
![[FAQs for novices on the road] understand program design step by step](/img/33/24ced00918bc7bd59f504cf1a73827.jpg)
[FAQs for novices on the road] understand program design step by step

Echart柱状图:堆叠柱状图value格式化显示

El form form verification

Detailed explanation of PHP distributed transaction principle

Solutions to common problems in small program development

JVM Foundation

Detailed explanation of Yanghui triangle

自定义View —— 可伸展的CollapsExpendView

RN Metro packaging process and sentry code monitoring
随机推荐
Echart矩形树图:简单实现矩形树图
【新手上路常见问答】一步一步理解程序设计
MFS详解(六)——MFS Chunk Server服务器安装与配置
Wechat applet (pull-down refresh data) novice to
Rk3399 hid gadget configuration
楊輝三角形詳解
c语言对文件相关的处理和应用
The title of the WebView page will be displayed in the top navigation bar of the app. How to customize
Using the shutter floor database framework
AI实现亲人“复活”|老照片修复|老照片上色,免费APP推荐
Uniapp (upload local pictures, preview pictures, convert Base64 format, upload audio files)
RFID process management solution for electroplating fixture
自定义View —— 可伸展的CollapsExpendView
Recommend a capacity expansion tool to completely solve the problem of insufficient disk space in Disk C and other disks
‘ipconfig‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。
[one · data 𞓜 simple implementation of the leading two-way circular linked list]
Relationship between fragment lifecycle and activity
动态链接库嵌套样例
Echart histogram: X-axis displays value, Y-axis displays category
You should consider upgrading via