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时会触发此方法。
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方法,查看一下文档:
则交给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能够这样处理吗?其实需要我们进行细化处理。
未完待续。。。