Android,java 层的Exception,Crash机制

一:关于Exception

我们在写程序是都会遇到异常处理问题,比如:下面一段代码

public static HttpEntity getHttpEntity2(String url){
		HttpClient client = new DefaultHttpClient();
        HttpGet get = new HttpGet(url);
        HttpResponse response=null;
        try {
			response = client.execute(get);
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
        
        HttpEntity entity=null;
        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
			entity = response.getEntity();
        }
        return entity;
	}

这是一段使用HttpClient进行网络请求获取Entity代码,这里我们只关注异常部分,出现两个异常,有时代码里会出现更多异常,会有一部分人这么改:

public static HttpEntity getHttpEntity2(String url){
		HttpClient client = new DefaultHttpClient();
        HttpGet get = new HttpGet(url);
        HttpResponse response=null;
        try {
			response = client.execute(get);
		} catch (Exception e) {
			e.printStackTrace();
		}
        
        HttpEntity entity=null;
        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
			entity = response.getEntity();
        }
        return entity;
	}

把所有的异常统一使用Exception捕获,统一处理。这样做看起来程序变得很简单,但是这样做真的好么?在刚开始接触异常处理时,我也这么去处理,觉得很方便,现在看来这样处理的人并不真正的了解异常机制,java提供的异常机制比较全面,如果我们只使用Exception去处理所有的异常,那就与异常机制设立违背了,异常机制就是当程序发送异常时我们按照异常类型,判断并修复对应的错误,保证程序正常能执行下去,全部使用Exception处理并不能确定是那种问题错误发送,异常处理不是打印log就完了,必须要进行合理的修复处理,最好的处理方式是对外抛出,谁使用,谁处理,我认为这是最合理的方式。因为不同使用者可以采取不一样的处理方式的需求,而不是把处理方式写死。

改之后的代码:

public static HttpEntity getHttpEntity(String url) throws ClientProtocolException, IOException{
		 HttpClient client = new DefaultHttpClient();
         HttpGet get = new HttpGet(url);
         HttpResponse response=null;
         response = client.execute(get);
         
         HttpEntity entity=null;
         if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
			entity = response.getEntity();
         }
         return entity;
	}
这样更佳灵活,调用者按照异常分类分别处理,不要使用一个Exception全部处理。

这里再说一下Exception,Exception分为两种

1,CheckException:在编写代码或编译时会发生错误提示或警告,我们必须对这种异常进行try_catch显示处理,例如:IOException

2,RuntimeException:我们不写Try_catch时也不会提示错误,当但程序运行时发生了错误,程序会发生crash结束运行,我们看看有哪些

喔!还真不少,看几个常见的ArithmeticException,ArrayIndexOutOfBoundsException,NullPointerException,是我们熟知的异常,当发生这类Exception,程序会创建一个Exception交给异常机制系统处理,异常机制会检测是否有对应的Exception处理(从产生Exception开始一直到调用者),如果我们没有捕获,并进行修复处理时,

程序停止向下运行,发生crash进程终止。


二:关于Crash机制

1,在程序发生crash时会触发uncaughtException(Thread thread, Throwable ex),通常我们会在这里进行收集crash信息上报,一般形式

class ExceptionHandler implements Thread.UncaughtExceptionHandler{
		@Override
		public void uncaughtException(Thread t, Throwable e) {
			System.out.println("exception="+e.getMessage());
			//写入文件,或上传
		}
	}

Java,Android异常机制默认ExceptionHandle为null,只是在控制台输出Log信息,就结束了,所以我们需要自己实现ExceptionHandle。

我们看一段代码:

public static void main(String[] args) {
		Main m=new Main();
		try{
			m.testException();
		}catch(Exception e){
		m.print("Exception Out: =="+e.getMessage());
		}
		m.print("MainThread execute end!");
	}
	
	void testException(){
		ExThread th=new ExThread();
	//	th.setUncaughtExceptionHandler(new ExeceptionHandler());
		th.start();
	}
	
	class ExThread extends Thread{
		int[] a=new int[5];
		@Override
		public void run() {
			print("exThread execute start!");
			for (int i=0;i<a.length+1;i++){
				print(a[i]);
			}
			print("exThread execute end!");
		}
	}

我们可以看到异常并没有被捕获的,异常信息显示出Thread-0,ArrayIndexOutOfBound,从这里我们可以发现,在不同Thread内发生的异常是不能在Thread外捕获到的,即异常处理范围是在线程栈内处理,栈外无法获取。

好,我们把setUncaughtExceptionHandler注释打开

可以看到UncaughtExceptionHandler异常捕获到了crash Exception了。好了这下理解了为啥setUncaughtExceptionHandler是在Thread类里了,我们再看一下文档:

可以看到默认实现为null,当Thread 由于未捕获Exception terminal时会触发此方法。


通常网上给出捕获crash Excption 是这样处理:在Application内onCreate初始化并设置:

public class AppContextImpl extends Application{

	@Override
	public void onCreate() {
		super.onCreate();
		initExceptionHandler();
	}
	
	private Thread.UncaughtExceptionHandler mDefaultHandler;
	void initExceptionHandler(){
		 mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); 
		 Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(this));
	}

为何这样设置呢?

ok,我们这里再把Example修改一下:

public static void main(String[] args) {
		Main m=new Main();
		m.testException();
		Thread.setDefaultUncaughtExceptionHandler(new ExeceptionHandler());
	}
	
	void testException(){
		ExThread th=new ExThread();
	//	th.setUncaughtExceptionHandler(new ExeceptionHandler());
		th.start();
	}

运行输出:

咦!居然在Thread外被捕获了!这是为何?我们首先看看这个Thread.setDefaultUncaughtExceptionHandler发现是Thread一个static方法,查看一下文档:


明白了,当一个crash发送时,首先在对应Thread的UncaughtExceptionHandler处理,如果UncaughtExceptionHandler为null,

则交给DefaultUncaughtExceptionHandler处理,注意!DefaultUncaughtExceptionHandler为所有的Thread共有,为兜底crash Exception 捕获处理的Handle。


嗯,整体的crash机制问题大概了解差不多,随之而来会有一个疑问,那就是当process 发生 crash后,此时Process已经terminal and dead,

那为什么程序还能继续执行将Exception写入文件,发送Exception给服务器呢?此时是由谁来控制呢?

有人可能会说是system来控制,可以这么认为,但是不够准确,准确来说是由Runtime System进行程序控制。

对于Runtime System 介绍可参考https://en.wikipedia.org/wiki/Runtime_system

这里简单说一下:运行时系统,是在程序创建时就会有一个对应的Runtime创建,用于对程序周期进行维护。不仅是java,Android,c++等其它语言也都有类似的功能,此外Runtime还提供类型检查,调试,代码生成与优化,程序与硬件(屏幕,键盘)及驱动(打印)访问也是通过Runtime来完成的。

我们可以通过Runtime.getRuntime()获取其实例,;可以用来执行某些系统命令,好,接下来说重点,就是当程序crash后,Process 被终止,剩下的工作就会交给Runtime去处理,包括异常信息记录,资源的清理工作等问题,保证系统正常稳定。


在自己创建Thread中我们知道如何捕获crash信息,如果是线程池内的Tread能够这样处理吗?其实需要我们进行细化处理。

未完待续。。。



posted @ 2016-07-28 20:44  HappyCode002  阅读(387)  评论(0编辑  收藏  举报