异常捕获 Thread.UncaughtExceptionHandler

setUncaughtExceptionHandler

public void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
1
1
 
1
public void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
设置该线程 由于未捕获到异常而突然终止时调用的处理程序。
通过明确设置 未捕获到的异常处理程序,线程可以完全控制它 对未捕获到的异常作出响应的方式。 
如果没有设置这样的处理程序,则该线程的 ThreadGroup 对象将充当其处理程序。

public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler()
1
1
 
1
public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler()
返回该线程由于未捕获到异常而突然终止时调用的处理程序。
如果该线程尚未明确设置未捕获到的异常处理程序,则返回该线程的 ThreadGroup 对象,除非该线程已经 终止,在这种情况下,将返回 null。

setDefaultUncaughtExceptionHandler

public static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
1
1
 
1
public static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
设置当线程由于未捕获到异常而突然终止, 并且没有为该线程定义其他处理程序时所调用的默认处理程序。

未捕获到的异常处理 首先由线程控制,然后由线程的 ThreadGroup 对象控制,最后由未捕获到的 默认异常处理程序控制。

如果线程不设置明确的未捕获到的异常处理程序,并且该线程的 线程组(包括父线程组)未特别指定其 uncaughtException 方法,则将调用 默认处理程序的 uncaughtException 方法

通过设置未捕获到的默认异常处理程序,应用程序可以 为那些已经接受系统提供的任何“默认”行为的线程改变未捕获到的异常处理方式(如记录到某一特定设备或文件)。

请注意,未捕获到的默认异常处理程序通常 不应顺从该线程的 ThreadGroup 对象,因为这可能导致无限递归。

public static Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler()
1
1
 
1
public static Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler()
返回线程由于未捕获到异常而突然终止时调用的默认处理程序。如果返回值为 null,则没有默认处理程序。

Thread.UncaughtExceptionHandler

public static interface Thread.UncaughtExceptionHandler
1
1
 
1
public static interface Thread.UncaughtExceptionHandler
所有已知实现类: ThreadGroup

当 Thread 因未捕获的异常而突然终止时,调用处理程序的接口。

当某一线程因未捕获的异常而即将终止时,Java 虚拟机将使用 Thread.getUncaughtExceptionHandler() 查询该线程以获得其 UncaughtExceptionHandler 的线程,并调用处理程序的 uncaughtException 方法,将 线程和异常作为参数传递。

如果某一线程没有明确设置其 UncaughtExceptionHandler,则将它的 ThreadGroup 对象作为其 UncaughtExceptionHandler。如果 ThreadGroup 对象对处理异常没有什么特殊要求,那么它可以将调用转发给默认的未捕获异常处理程序。

void uncaughtException(Thread t, Throwable e) 
1
1
 
1
void uncaughtException(Thread t, Throwable e) 
当给定线程因给定的未捕获异常而终止时,调用该方法。
Java 虚拟机将忽略该方法抛出的任何异常。

JAVA 测试案例

public class Test {
	public static void main(String[] args) {
		setDefaultUncaughtExceptionHandler();
		test();
	}

	private static void test() {
		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("子线程异常前");
				System.out.println(1 / 0);
			}
		}).start();
		System.out.println("当前线程异常前");
		System.out.println(1 / 0);
		System.out.println("异常后的代码不能执行了");
	}

	private static void setDefaultUncaughtExceptionHandler() {
		UncaughtExceptionHandler currentHandler = new UncaughtExceptionHandler() {
			@Override
			public void uncaughtException(Thread t, Throwable e) {
				System.out.println("【当前线程的Handler处理异常信息】" + t.toString() + "\n" + e.getMessage());
			}
		};
		UncaughtExceptionHandler defaultHandler = new UncaughtExceptionHandler() {
			@Override
			public void uncaughtException(Thread t, Throwable e) {
				StringWriter writer = new StringWriter();
				PrintWriter printWriter = new PrintWriter(writer);
				printWriter.write("start------------\n");
				e.printStackTrace(printWriter);
				printWriter.write("------------end");
				printWriter.close();
				System.out.println("【默认的Handler处理异常信息】" + writer.getBuffer().toString());
			}
		};
		Thread.currentThread().setUncaughtExceptionHandler(currentHandler);
		Thread.setDefaultUncaughtExceptionHandler(defaultHandler);
	}
}
x
42
 
1
public class Test {
2
    public static void main(String[] args) {
3
        setDefaultUncaughtExceptionHandler();
4
        test();
5
    }
6
 
          
7
    private static void test() {
8
        new Thread(new Runnable() {
9
            @Override
10
            public void run() {
11
                System.out.println("子线程异常前");
12
                System.out.println(1 / 0);
13
            }
14
        }).start();
15
        System.out.println("当前线程异常前");
16
        System.out.println(1 / 0);
17
        System.out.println("异常后的代码不能执行了");
18
    }
19
 
          
20
    private static void setDefaultUncaughtExceptionHandler() {
21
        UncaughtExceptionHandler currentHandler = new UncaughtExceptionHandler() {
22
            @Override
23
            public void uncaughtException(Thread t, Throwable e) {
24
                System.out.println("【当前线程的Handler处理异常信息】" + t.toString() + "\n" + e.getMessage());
25
            }
26
        };
27
        UncaughtExceptionHandler defaultHandler = new UncaughtExceptionHandler() {
28
            @Override
29
            public void uncaughtException(Thread t, Throwable e) {
30
                StringWriter writer = new StringWriter();
31
                PrintWriter printWriter = new PrintWriter(writer);
32
                printWriter.write("start------------\n");
33
                e.printStackTrace(printWriter);
34
                printWriter.write("------------end");
35
                printWriter.close();
36
                System.out.println("【默认的Handler处理异常信息】" + writer.getBuffer().toString());
37
            }
38
        };
39
        Thread.currentThread().setUncaughtExceptionHandler(currentHandler);
40
        Thread.setDefaultUncaughtExceptionHandler(defaultHandler);
41
    }
42
}
运行结果
子线程异常前
当前线程异常前
【当前线程的Handler处理异常信息】Thread[main,5,main]
/ by zero
【默认的Handler处理异常信息】start------------
java.lang.ArithmeticException: / by zero
	at Test$1.run(Test.java:16)
	at java.lang.Thread.run(Thread.java:745)
------------end
 
1
子线程异常前
2
当前线程异常前
3
【当前线程的Handler处理异常信息】Thread[main,5,main]
4
/ by zero
5
【默认的Handler处理异常信息】start------------
6
java.lang.ArithmeticException: / by zero
7
    at Test$1.run(Test.java:16)
8
    at java.lang.Thread.run(Thread.java:745)
9
------------end

Android 中的一个实用案例

异常处理类
/**
 * Desc:采集崩溃日志
 *
 * @author <a href="http://www.cnblogs.com/baiqiantao">白乾涛</a><p>
 * @tag 崩溃日志<p>
 * @date 2018/5/2 14:12 <p>
 */
public class CrashHandler implements Thread.UncaughtExceptionHandler {
	private static final String LOG_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/crashLog/";
	private Application application;
	
	private static CrashHandler instance = new CrashHandler();
	
	private CrashHandler() {//构造方法私有
	}
	
	public static CrashHandler getInstance() {
		return instance;
	}
	
	public void init(Application application) {
		this.application = application;
		Thread.setDefaultUncaughtExceptionHandler(instance);//设置该CrashHandler为系统默认的
	}
	
	@Override
	public void uncaughtException(Thread thread, Throwable ex) {
		saveInfoToFile(collectCrashInfo(ex));//保存错误信息
		new Thread() {
			@Override
			public void run() {
				Looper.prepare();
				Toast.makeText(application, "程序开小差了,将会在2秒后退出", Toast.LENGTH_SHORT).show();//使用Toast来显示异常信息
				Looper.loop();
			}
		}.start();
		SystemClock.sleep(2000);//延迟2秒杀进程
		android.os.Process.killProcess(android.os.Process.myPid());
		System.exit(0);
	}
	
	private String collectCrashInfo(Throwable ex) {
		if (ex == null) return "";
		
		Writer writer = new StringWriter();
		PrintWriter printWriter = new PrintWriter(writer);
		ex.printStackTrace(printWriter);
		Throwable throwable = ex.getCause();
		while (throwable != null) {
			throwable.printStackTrace(printWriter);
			throwable = throwable.getCause();//逐级获取错误信息
		}
		String crashInfo = writer.toString();
		Log.i("bqt", "【错误信息】" + crashInfo);
		printWriter.close();
		return crashInfo;
	}
	
	private void saveInfoToFile(String crashInfo) {
		try {
			File dir = new File(LOG_PATH);
			if (!dir.exists()) {
				dir.mkdirs();
			}
			String date = new SimpleDateFormat("yyyy.MM.dd_HH_mm_ss", Locale.getDefault()).format(new Date());
			String fileName = LOG_PATH + "crash_" + date + ".txt";
			FileWriter writer = new FileWriter(fileName);//如果保存失败,很可能是没有写SD卡权限
			writer.write(crashInfo);
			writer.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
//如果保存失败,很可能是没有写SD卡权限
x
 
1
/**
2
 * Desc:采集崩溃日志
3
 *
4
 * @author <a href="http://www.cnblogs.com/baiqiantao">白乾涛</a><p>
5
 * @tag 崩溃日志<p>
6
 * @date 2018/5/2 14:12 <p>
7
 */
8
public class CrashHandler implements Thread.UncaughtExceptionHandler {
9
    private static final String LOG_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/crashLog/";
10
    private Application application;
11
    
12
    private static CrashHandler instance = new CrashHandler();
13
    
14
    private CrashHandler() {//构造方法私有
15
    }
16
    
17
    public static CrashHandler getInstance() {
18
        return instance;
19
    }
20
    
21
    public void init(Application application) {
22
        this.application = application;
23
        Thread.setDefaultUncaughtExceptionHandler(instance);//设置该CrashHandler为系统默认的
24
    }
25
    
26
    @Override
27
    public void uncaughtException(Thread thread, Throwable ex) {
28
        saveInfoToFile(collectCrashInfo(ex));//保存错误信息
29
        new Thread() {
30
            @Override
31
            public void run() {
32
                Looper.prepare();
33
                Toast.makeText(application, "程序开小差了,将会在2秒后退出", Toast.LENGTH_SHORT).show();//使用Toast来显示异常信息
34
                Looper.loop();
35
            }
36
        }.start();
37
        SystemClock.sleep(2000);//延迟2秒杀进程
38
        android.os.Process.killProcess(android.os.Process.myPid());
39
        System.exit(0);
40
    }
41
    
42
    private String collectCrashInfo(Throwable ex) {
43
        if (ex == null) return "";
44
        
45
        Writer writer = new StringWriter();
46
        PrintWriter printWriter = new PrintWriter(writer);
47
        ex.printStackTrace(printWriter);
48
        Throwable throwable = ex.getCause();
49
        while (throwable != null) {
50
            throwable.printStackTrace(printWriter);
51
            throwable = throwable.getCause();//逐级获取错误信息
52
        }
53
        String crashInfo = writer.toString();
54
        Log.i("bqt", "【错误信息】" + crashInfo);
55
        printWriter.close();
56
        return crashInfo;
57
    }
58
    
59
    private void saveInfoToFile(String crashInfo) {
60
        try {
61
            File dir = new File(LOG_PATH);
62
            if (!dir.exists()) {
63
                dir.mkdirs();
64
            }
65
            String date = new SimpleDateFormat("yyyy.MM.dd_HH_mm_ss", Locale.getDefault()).format(new Date());
66
            String fileName = LOG_PATH + "crash_" + date + ".txt";
67
            FileWriter writer = new FileWriter(fileName);//如果保存失败,很可能是没有写SD卡权限
68
            writer.write(crashInfo);
69
            writer.close();
70
        } catch (Exception e) {
71
            e.printStackTrace();
72
        }
73
    }
74
}
获取的异常信息
java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference
        at com.bqt.test.MainActivity.onListItemClick(MainActivity.java:34)
        at android.app.ListActivity$2.onItemClick(ListActivity.java:319)
        at android.widget.AdapterView.performItemClick(AdapterView.java:339)
        at android.widget.AbsListView.performItemClick(AbsListView.java:1705)
        at android.widget.AbsListView$PerformClick.run(AbsListView.java:4171)
        at android.widget.AbsListView$13.run(AbsListView.java:6735)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6682)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1534)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1424)
14
 
1
java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference
2
        at com.bqt.test.MainActivity.onListItemClick(MainActivity.java:34)
3
        at android.app.ListActivity$2.onItemClick(ListActivity.java:319)
4
        at android.widget.AdapterView.performItemClick(AdapterView.java:339)
5
        at android.widget.AbsListView.performItemClick(AbsListView.java:1705)
6
        at android.widget.AbsListView$PerformClick.run(AbsListView.java:4171)
7
        at android.widget.AbsListView$13.run(AbsListView.java:6735)
8
        at android.os.Handler.handleCallback(Handler.java:751)
9
        at android.os.Handler.dispatchMessage(Handler.java:95)
10
        at android.os.Looper.loop(Looper.java:154)
11
        at android.app.ActivityThread.main(ActivityThread.java:6682)
12
        at java.lang.reflect.Method.invoke(Native Method)
13
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1534)
14
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1424)
2018-6-1




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值