val default = Thread.getDefaultUncaughtExceptionHandler() Thread.setDefaultUncaughtExceptionHandler { t, E -> log. e("Uncaught", "exception message: "+ e.m essage) / / will be abnormal return receipt to the original registered handler default. The uncaughtException (t, e)}Copy the code
The above is a very simple piece of code, often used in Java exception global capture, but MY question is, how he achieved global capture, with such a question, let’s take a look at the code.
Ultimately, we see a static method getDefaultUncaughtExceptionHandler is who call, saw all the classes under the call of class, only the ThreadGroup on most:
In the case of the parent is empty, it will call the callback to invoke getDefaultUncaughtExceptionHandler anomaly, and then continue to see ThreadGroup uncaughtException by whom is triggered, searched a circle, None of them are reliable. As I hesitated, I glanced at the notes and miraculously found:
- Called by the Java Virtual Machine when a thread in this
- thread group stops because of an uncaught exception, and the thread
- does not have a specific {[@link ](/link%20)Thread.UncaughtExceptionHandler}
- installed.
Copy the code
The JVM calls this method when an uncaught exception causes a thread in a thread group to stop. Let’s search the JVM source code to see how this method is triggered.
The JavaThread::exit method in thread. CPP of the Hotspot VIRTUAL machine source code finds this code with a comment:
The Thread calls the exit exits, if there is an uncaught exception, will be the Thread. DispatchUncaughtException method, and then we continue to follow this method:
Then call the current thread’s uncaughtException to distribute the exception:
Interestingly, if we do not set UncaughtExceptionHandler to the current thread, we will pass this exception to the ThreadGroup of the current thread. If we set to the current thread UncaughtExceptionHandler, the current thread exception happens, never threw getDefaultUncaughtExceptionHandler, this function is suitable for exceptions to capture the current thread.
Finally returned to the ThreadGroup. We see at first UncaughtExceptionHandler method, stick back to the original figure to analysis:
This place will continue to judge whether the parent is null, the parent is a ThreadGroup, realized ThreadGroup Thread. UncaughtExceptionHandler interface. If the parent of the system is null, then the else branch is used. Retrieve getDefaultUncaughtExceptionHandler static variables in the Thread, triggering uncaughtException method, because we set the static variables in the Activity, so, we had received this exception.
The little knowledge
1. How to catch exceptions without exiting
val default = Thread.getDefaultUncaughtExceptionHandler() Log.e("Uncaught", "Uncaught handler: "+ default) // Uncaught handler: com.android.internal.os.RuntimeInit$KillApplicationHandler@21f02a3 Thread.setDefaultUncaughtExceptionHandler { t, E - > / / abnormal return receipt to the original registered handler. / / the default uncaughtException (t, e)}Copy the code
After an exception is caught, nothing is handled. However, doing so is very unsophisticated and will cause other frameworks to fail to catch exception reports through previously set static variables. Default is RuntimeInit, which does killProcess when an exception is caught.
2, how to catch the specified thread exception:
val thread = Thread {
val a = 1/0
}
thread.setUncaughtExceptionHandler { t, e ->
Log.e("Uncaught", "Uncaught trace: "+ e.message)
}
thread.start()
Copy the code
3, ThreadGroup and Thread relationship structure
- The parent of a Thread is specified when a new Thread is created, and constructs a custom ThreadGroup. By default, the ThreadGroup that created the current Thread is used
- Thread[] is added to a ThreadGroup when a call to start the Thread is made
- The parent of a ThreadGroup is specified when a new ThreadGroup is created to construct a customizable ThreadGroup that uses the current thread’s ThreadGroup by default