• 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能够这样处理吗?其实需要我们进行细化处理。

    未完待续。。。



  • 相关阅读:
    HDU 3008 DP
    XCode 7 高速切换代码窗体和文档窗体
    软工视频(37~46)-软件管理
    js 实现对ajax请求面向对象的封装
    sgu101Domino
    如何查看Eclipse的数字版的版本(转)
    Java的历史和大事记
    Eclipse使用前准备(转)
    启动 Eclipse 弹出“Failed to load the JNI shared library jvm.dll”错误的解决方法!
    如何快速配好java环境变量和查看电脑上安装JDK的版本位数
  • 原文地址:https://www.cnblogs.com/happyxiaoyu02/p/6150739.html
Copyright © 2020-2023  润新知