異常

異常的體系

exception

異常:是在運(yùn)行時(shí)期發(fā)生的不正常情況泼橘。 在java中用類(lèi)的形式對(duì)不正常情況進(jìn)行了描述和封裝對(duì)象涝动。描述不正常的情況的類(lèi),就稱(chēng)為異常類(lèi)炬灭。

  1. 以前正常流程代碼和問(wèn)題處理代碼相結(jié)合醋粟,現(xiàn)在將正常流程代碼和問(wèn)題處理代碼分離,提高閱讀性。
  2. 其實(shí)異常就是java通過(guò)面向?qū)ο蟮乃枷雽?wèn)題封裝成了對(duì)象米愿,用異常類(lèi)對(duì)其進(jìn)行描述厦凤。
  3. 不同的問(wèn)題用不同的類(lèi)進(jìn)行具體的描述。比如角標(biāo)越界育苟、空指針異常等等较鼓。
  4. 問(wèn)題很多,意味著描述的類(lèi)也很多违柏,將其共性進(jìn)行向上抽取博烂,形成了異常體系。

不正常情況分成了兩大類(lèi):

Throwable:無(wú)論是error漱竖,還是異常禽篱、問(wèn)題,問(wèn)題發(fā)生就應(yīng)該可以拋出馍惹,讓調(diào)用者知道并處理动遭。

該體系的特點(diǎn)就在于Throwable及其所有的子類(lèi)都具有可拋性息楔。

可拋性到底指的是什么呢急鳄?怎么體現(xiàn)可拋性呢银酗?

其實(shí)是通過(guò)兩個(gè)關(guān)鍵字來(lái)體現(xiàn)的:throws、throw勤众,凡是可以被這兩個(gè)關(guān)鍵字所操作的類(lèi)和對(duì)象都具備可拋性舆绎。

  1. 一般不可處理的:Error

    特點(diǎn):是由jvm拋出的嚴(yán)重性問(wèn)題鲤脏。

    這種問(wèn)題發(fā)生们颜,一般不針對(duì)性處理,直接修改程序猎醇。

  2. 可以處理的:Exception

    該體系的特點(diǎn):子類(lèi)的后綴名都是用其父類(lèi)名作為后綴窥突,閱讀性很強(qiáng)。

常見(jiàn)異常

異常 說(shuō)明
IndexOutOfBoundsException 角標(biāo)越界異常
NullPointerException 空指針異常
ConcurrentModificationException 并發(fā)修改異常
ClassCastException 類(lèi)型轉(zhuǎn)換異常
UnsupportedOperationException 不支持操作異常
NullPointerException 沒(méi)有元素異常
IllegalArgumentException 非法參數(shù)異常
IllegalAccessException 非法的訪問(wèn)異常

Throwable常用方法

方法聲明 功能描述
getMessage() 獲取異常信息硫嘶,返回字符串阻问。
toString() 獲取異常類(lèi)名和異常信息,返回字符串沦疾。
printStackTrace() 獲取異常類(lèi)名和異常信息称近,以及異常出現(xiàn)在程序中的位置,返回值void哮塞。
printStackTrace(PrintStreams) 通常用該方法將異常內(nèi)容保存在日志文件中刨秆,以便查閱。

示例:

class Demo{
   public static int method(int[] arr, int index){
       if(arr == null){
           throw new NullPointerException("數(shù)組的引用不能為空忆畅!");
       }
       if(index >= arr.length ){
           throw new ArrayIndexOutOfBoundsException("數(shù)組的角標(biāo)越界:" +
                   index);
       }
       return arr[index];
   }
}
class ExceptionDemo{
   public static void main(String[] args){
       int[] arr = new int[3];
       Demo.method(arr,30);
   }
}

運(yùn)行結(jié)果:

exception

自定義異常

可以自定義出現(xiàn)的問(wèn)題稱(chēng)為自定義異常衡未。
對(duì)于角標(biāo)為負(fù)數(shù)的情況,可以用負(fù)數(shù)角標(biāo)異常來(lái)表示,負(fù)數(shù)角標(biāo)這種異常在java中并沒(méi)有定義過(guò)缓醋。
那就按照java異常的創(chuàng)建思想如失,面向?qū)ο螅瑢⒇?fù)數(shù)角標(biāo)進(jìn)行自定義描述送粱,并封裝成對(duì)象褪贵。
這種自定義的問(wèn)題描述稱(chēng)為自定義異常。

注意事項(xiàng):

如果讓一個(gè)類(lèi)成為異常類(lèi)抗俄,必須要繼承異常體系竭鞍,因?yàn)橹挥谐蔀楫惓sw系的子類(lèi)才有資格具備可拋性,才可以被兩個(gè)關(guān)鍵字所操作:throws橄镜、throw偎快。

自定義類(lèi)繼承Exception或者其子類(lèi),通過(guò)構(gòu)造函數(shù)定義異常信息洽胶。

示例:

Class DemoException extends Exception

{
    DemoException(Stringmessage)
    {
        super(message);
    }
}

通過(guò)throw將自定義異常拋出晒夹。

自定義類(lèi)繼承Exception,作為基類(lèi)

public class HMException extends Exception {

    public HMException() {
        super();
        // TODO Auto-generated constructor stub
    }

    public HMException(String detailMessage, Throwable throwable) {
        super(detailMessage, throwable);
        // TODO Auto-generated constructor stub
    }

    public HMException(String detailMessage) {
        super(detailMessage);
        // TODO Auto-generated constructor stub
    }

    public HMException(Throwable throwable) {
        super(throwable);
        // TODO Auto-generated constructor stub
    }

}

子類(lèi)

public class HMAException extends HMException {

}

public class HMBException extends HMException {

}

public class HMCException extends HMException {

}

public class HMDException extends HMException {

}

ExceptionHandler異常處理器

public class ExceptionHandler {
    /**
     * 根據(jù)不同的HMException給用戶具體的提示
     * @param e
     */
    public static void toastByHMException(Context context, HMException e) {
        int errCode = 0;
        // errCode 具體化
        if (e instanceof HMAException) {
            errCode = 1;
        } else if (e instanceof HMBException) {
            errCode = 2;
        } else if (e instanceof HMCException) {
            errCode = 3;

        } else if (e instanceof HMDException) {
            errCode = 4;
        }
        // 根據(jù)不同的errcode給用戶做提示
        toastByErrCode(context, errCode);
    }

    private static void toastByErrCode(Context context, int errCode) {
        String content = "";
        switch (errCode) {
        case 1:
            content = "程序出現(xiàn)了HMAException";
            break;
        case 2:
            content = "程序出現(xiàn)了HMBException";
            break;
        case 3:
            content = "程序出現(xiàn)了HMCException";
            break;
        case 4:
            content = "程序出現(xiàn)了HMDException";
            break;

        default:
            break;
        }
        Toast.makeText(context, content, 0).show();
    }
}

HMApi

public class HMApi {
    public void method1() throws HMException {
        // 模擬,某一個(gè)時(shí)刻出現(xiàn)了HMAException
        throw new HMAException();
    }

    public void method2() throws HMException {
        // 模擬,某一個(gè)時(shí)刻出現(xiàn)了HMBException
        throw new HMBException();
    }

    public void method3() throws HMException {
        // 模擬,某一個(gè)時(shí)刻出現(xiàn)了HMCException
        throw new HMCException();
    }

    public void method4() throws HMException {
        // 模擬,某一個(gè)時(shí)刻出現(xiàn)了HMDException
        throw new HMDException();
    }
}

MainActivity.class姊氓,使用自定義異常

public class MainActivity extends Activity {

    private HMApi   mApi;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mApi = new HMApi();
    }

    public void method1(View v) {
        try {
            mApi.method1();
        } catch (HMException e) {
            e.printStackTrace();
            ExceptionHandler.toastByHMException(MainActivity.this, e);
        }
    }

    public void method2(View v) {
        try {
            mApi.method2();
        } catch (HMException e) {
            e.printStackTrace();
            ExceptionHandler.toastByHMException(MainActivity.this, e);
        }
    }

    public void method3(View v) {
        try {
            mApi.method3();
        } catch (HMException e) {
            e.printStackTrace();
            ExceptionHandler.toastByHMException(MainActivity.this, e);
        }
    }

    public void method4(View v) {
        try {
            mApi.method4();
        } catch (HMException e) {
            e.printStackTrace();
            ExceptionHandler.toastByHMException(MainActivity.this, e);
        }
    }

}

throws和throw的區(qū)別

  1. throws用于標(biāo)識(shí)函數(shù)暴露出的異常類(lèi)丐怯,并且可以拋出多個(gè),用逗號(hào)分隔翔横。throw用于拋出異常對(duì)象

  2. thorws用在函數(shù)上读跷,后面跟異常類(lèi)名。throw用在函數(shù)內(nèi)禾唁,后面跟異常對(duì)象效览。

定義功能方法時(shí),需要把出現(xiàn)的問(wèn)題暴露出來(lái)讓調(diào)用者去處理荡短,那么就通過(guò)throws在函數(shù)上標(biāo)識(shí)丐枉。

在功能方法內(nèi)部出現(xiàn)某種情況,程序不能繼續(xù)運(yùn)行掘托,需要進(jìn)行跳轉(zhuǎn)時(shí)瘦锹,就用throw把異常對(duì)象拋出。

示例:

class FuShuIndexException extends Exception {
    FuShuIndexException() {
    }

    FuShuIndexException(String msg) {
        super(msg);
    }
}

class Demo {
    public static int method(int[] arr, int index) throws FuShuIndexException {
        if (index < 0) {
            throw new FuShuIndexException ("數(shù)組的角標(biāo)是負(fù)數(shù)啦闪盔!");
        }
        return arr[index];
    }
}

class ExceptionDemo {
    public static void main(String[] args) throws FuShuIndexException {
        int[] arr = new int[3];
        Demo.method(arr, -30);
    }
}

運(yùn)行結(jié)果:

exception

異常的分類(lèi):

編譯時(shí)被檢測(cè)異常

只要是Exception和其子類(lèi)都是弯院,除了特殊子類(lèi)RuntimeException體系。這種問(wèn)題一旦出現(xiàn)泪掀,希望在編譯時(shí)就進(jìn)行檢測(cè)听绳,讓這種問(wèn)題有對(duì)應(yīng)的處理方式。這樣的問(wèn)題都可以針對(duì)性的處理族淮。

編譯時(shí)不檢測(cè)異常(運(yùn)行時(shí)異常)

就是Exception中的RuntimeException和其子類(lèi)辫红。這種問(wèn)題的發(fā)生凭涂,無(wú)法讓功能繼續(xù),運(yùn)算無(wú)法運(yùn)行贴妻,更多是因?yàn)檎{(diào)用的原因?qū)е碌幕蛘咭l(fā)了內(nèi)部狀態(tài)的改變導(dǎo)致的切油。

那么這種問(wèn)題一般不處理,直接編譯通過(guò)名惩,在運(yùn)行時(shí)澎胡,讓調(diào)用者調(diào)用時(shí)的程序強(qiáng)制停止,讓調(diào)用者對(duì)代碼進(jìn)行調(diào)整娩鹉。

所以自定義異常時(shí)攻谁,要么繼承Exception,要么繼承RuntimeException弯予。

示例:

class FuShuIndexException extends RuntimeException {
    FuShuIndexException() {
    }

    FuShuIndexException(String msg) {
        super(msg);
    }
}

class Demo {
    public static int method(int[] arr, int index) {
        // RuntimeException沒(méi)有必要用throws拋出戚宦,并不是必須要處理
        if (index < 0) {
            throw new FuShuIndexException("數(shù)組的角標(biāo)是負(fù)數(shù)啦!");
        }
        return arr[index];
    }
}

運(yùn)行結(jié)果:

exception

注意事項(xiàng):

RuntimeException是那些可能在Java虛擬機(jī)正常運(yùn)行期間拋出的異常的超類(lèi)锈嫩∈苈ィ可能在執(zhí)行方法期間拋出但未被捕獲的RuntimeException的任何子類(lèi)都無(wú)需在throws子句中進(jìn)行聲明。

異常處理的捕捉形式

可以對(duì)異常進(jìn)行針對(duì)性處理的方式呼寸。具體格式是:

    try{
         //需要被檢測(cè)異常的代碼艳汽。
    }
    catch(異常類(lèi) 變量) //該變量用于接收發(fā)生的異常對(duì)象
    {
         //處理異常的代碼。
    }
    finally{
         //一定會(huì)執(zhí)行的代碼对雪;
    }

注意事項(xiàng):

finally代碼塊只有一種情況不會(huì)被執(zhí)行河狐,就是在之前執(zhí)行了System.exit(0)。

處理過(guò)程:

try 中檢測(cè)到異常會(huì)將異常對(duì)象傳遞給catch瑟捣,catch捕獲到異常進(jìn)行處理馋艺。
finally 里通常用來(lái)關(guān)閉資源。比如:數(shù)據(jù)庫(kù)資源蝶柿,IO資源等丈钙。

需要注意:try是一個(gè)獨(dú)立的代碼塊非驮,在其中定義的變量只在該變量塊中有效交汤。如果在try以外繼續(xù)使用,需要在try外建立引用劫笙,在try中對(duì)其進(jìn)行初始化芙扎。IO,Socket就會(huì)遇到填大。

示例:

class FuShuIndexException extends RuntimeException{
    FuShuIndexException(){}

    FuShuIndexException(String msg){
        super(msg);
    }
}

class Demo{
    public static int method(int[] arr, int index) throws
            NullPointerException,FuShuIndexException{
        if(arr == null)
            throw new NullPointerException("沒(méi)有任何數(shù)組實(shí)體");
        if(index < 0){
            throw new FuShuIndexException("數(shù)組的角標(biāo)是負(fù)數(shù)啦戒洼!");
        }
        return arr[index];
    }
}

class ExceptionDemo{
    public static void main(String[] args){
        int[] arr = new int[3];
        try{
            int num = Demo.method(arr,-30);
            System.out.println("num:" + num);
        } catch(NullPointerException e){
            System.out.println(e);
        } catch(FuShuIndexException e){
            System. out.println("message:" + e.getMessage());
            System.out.println("string:" + e);
            e.printStackTrace(); //jvm 默認(rèn)的異常處理機(jī)制就是調(diào)用異常對(duì)象的這個(gè)方法。
            System.out.println("負(fù)數(shù)角標(biāo)異常T驶H健寥掐!");
        } catch(Exception e){//Exception的catch放在最下面,先處理有針對(duì)性的異常
            System.out.println(e);
        }
        System.out.println("over" );
    }
}

運(yùn)行結(jié)果:

exception

異常處理的原則

  1. 函數(shù)內(nèi)容如果拋出需要檢測(cè)的異常磷蜀,那么函數(shù)上必須要聲明召耘。否則,必須在函數(shù)內(nèi)用try/catch捕捉褐隆,否則編譯失敗污它。

  2. 如果調(diào)用到了聲明異常的函數(shù),要么try/catch庶弃,要么throws衫贬,否則編譯失敗。

  3. 什么時(shí)候catch歇攻,什么時(shí)候throws呢固惯?

    功能內(nèi)容可以解決,用catch缴守。解決不了缝呕,用throws告訴調(diào)用者,由調(diào)用者解決斧散。

  4. 一個(gè)功能如果拋出了多個(gè)異常供常,那么調(diào)用時(shí),必須有對(duì)應(yīng)多個(gè)catch進(jìn)行針對(duì)性處理鸡捐。內(nèi)部有幾個(gè)需要檢測(cè)的異常栈暇,就拋幾個(gè)異常,拋出幾個(gè)箍镜,就catch幾個(gè)源祈。

示例:

 class Demo{
        public int show(int index) throws ArrayIndexOutOfBoundsException{
              if(index < 0)
                    throw new ArrayIndexOutOfBoundsException("越界啦!");
              int[] arr = new int[3];
              return arr[index];
        }
 }

 class ExceptionDemo{
        public static void main(String[] args){
             Demo d = new Demo();
             try{
                   int num = d.show(-3);
                   System.out.println("num = " + num);
              } catch(ArrayIndexOutOfBoundsException e){
                   System.out.println(e.toString());
                   System.exit(0);//退出jvm
              } finally{//通常用于關(guān)閉(釋放)資源
                   System.out.println("finally");//由于前面執(zhí)行了System.exit(0);色迂,故不會(huì)執(zhí)行此語(yǔ)句香缺。
              }
             System.out.println("over");
       }
 }

運(yùn)行結(jié)果:

exception

try catch finally 代碼塊組合特點(diǎn):

  1. try catch finally
  2. try catch(多個(gè)):當(dāng)沒(méi)有資源需要釋放時(shí),可以不用定義finally歇僧。
  3. try finally:異常無(wú)法直接catch處理图张,但是資源必須關(guān)閉。

示例:

 void show() throws Exception{
      try{
           //開(kāi)啟資源
           throw new Exception();
       }finally{
           //關(guān)閉資源
       }
 }

異常綜合案例

 /*
 畢老師用電腦上課诈悍。

 問(wèn)題領(lǐng)域中涉及兩個(gè)對(duì)象祸轮。
 畢老師,電腦侥钳。

 分析其中的問(wèn)題适袜。
 比如電腦藍(lán)屏,冒煙等舷夺。
 */
 class LanPingException extends Exception{
       LanPingException(String msg){
              super(msg);
       }
 }

 class MaoYanException extends Exception{
       MaoYanException(String msg){
              super(msg);
       }
 }

 class NoPlanException extends Exception{
       NoPlanException(String msg){
              super(msg);
       }
 }

 class Computer{
        private int state = 1;//0 2
        public void run() throws LanPingException,MaoYanException{
              if(state == 1)
                    throw new LanPingException("電腦藍(lán)屏啦苦酱!");
              if(state == 2)
                    throw new MaoYanException("電腦冒煙啦售貌!");
              System. out.println("電腦運(yùn)行");
        }
        public void reset(){
             state = 0;
             System.out.println("電腦重啟");
        }
 }

 class Teacher{
        private String name ;
        private Computer comp ;

        Teacher(String name){
              this.name = name;
              comp = new Computer();
        }

        public void prelect() throws NoPlanException{
              try{
                   comp.run();
                   System. out.println(name + "講課");
              } catch(LanPingException e){
                   System.out.println(e.toString());
                   comp.reset();
                   prelect();
              } catch(MaoYanException e){
                   System. out.println(e.toString());
                   test();
                    //可以對(duì)電腦進(jìn)行維修
                    throw new NoPlanException("課時(shí)進(jìn)度無(wú)法完成,原因:" + e.getMessage());
              }
        }
        public void test(){
             System.out.println("大家練習(xí)");
        }
 }

 class ExceptionDemo{
        public static void main(String[] args){
             Teacher t = new Teacher("畢老師");
              try{
                   t.prelect();
              } catch(NoPlanException e){
                   System.out.println(e.toString() + "......." );
                   System.out.println("換人");
              }
        }
 }

運(yùn)行結(jié)果:

exception

異常的注意事項(xiàng)

  1. RuntimeException以及其子類(lèi)如果在函數(shù)中被throw拋出疫萤,可以不用在函數(shù)上聲明趁矾。
  2. 子類(lèi)在覆蓋父類(lèi)方法時(shí),父類(lèi)的方法如果拋出了異常给僵,那么子類(lèi)的方法只能拋出父類(lèi)的異澈恋罚或者該異常的子類(lèi)。
  3. 如果父類(lèi)拋出多個(gè)異常帝际,那么子類(lèi)只能拋出父類(lèi)異常的子集蔓同。

簡(jiǎn)單說(shuō):子類(lèi)覆蓋父類(lèi)只能拋出父類(lèi)的異常或者子類(lèi)的子集蹲诀。如果父類(lèi)的方法沒(méi)有拋出異常斑粱,那么子類(lèi)覆蓋時(shí)絕對(duì)不能拋,就只能try脯爪。

異常常見(jiàn)問(wèn)題

1. try{ }里有一個(gè)return x語(yǔ)句则北,那么緊跟在這個(gè)try后的finally { }里的code會(huì)不會(huì)被執(zhí)行,什么時(shí)候被執(zhí)行痕慢,在return前還是后?

在return中間執(zhí)行尚揣,return x其實(shí)是先執(zhí)行了返回值計(jì)算,并把計(jì)算結(jié)果的地址保存在一個(gè)臨時(shí)的局部變量中掖举,然后開(kāi)始執(zhí)行finally子句快骗,finally執(zhí)行完畢后,再?gòu)南惹暗呐R時(shí)變量中取得返回地址塔次,返回方法的最終結(jié)果方篮。根據(jù)這樣的處理方式,當(dāng)我們?cè)噲D在finally子句中再行改變x的值時(shí)励负,已經(jīng)不會(huì)對(duì)方法的返回結(jié)果造成影響藕溅。

return并不是讓函數(shù)馬上返回,而是return語(yǔ)句執(zhí)行后继榆,將把返回結(jié)果放置進(jìn)函數(shù)棧中巾表,此時(shí)函數(shù)并不是馬上返回,它要執(zhí)行finally語(yǔ)句后才真正開(kāi)始返回

2. 運(yùn)行時(shí)異常runtime exception與一般異常checked exception有何異同裕照?

對(duì)于檢查異常攒发,編譯器強(qiáng)制要求我們?nèi)ry catch,否則編譯不通過(guò)晋南;運(yùn)行時(shí)異常我們可以不處理。這樣的異常由虛擬機(jī)接管羔砾。出現(xiàn)運(yùn)行時(shí)異常后负间,系統(tǒng)會(huì)把異常一直往上層拋偶妖,一直遇到處理代碼。如果不對(duì)運(yùn)行時(shí)異常進(jìn)行處理政溃,那么出現(xiàn)運(yùn)行時(shí)異常之后趾访,要么是線程中止,要么是主程序終止

異常表示程序運(yùn)行過(guò)程中可能出現(xiàn)的非正常狀態(tài)董虱,運(yùn)行時(shí)異常表示虛擬機(jī)的通常操作中可能遇到的異常扼鞋,是一種常見(jiàn)運(yùn)行錯(cuò)誤。java編譯器要求方法必須聲明拋出可能發(fā)生的非運(yùn)行時(shí)異常愤诱,但是并不要求必須聲明拋出未被捕獲的運(yùn)行時(shí)異常

UncaughtExceptionHandler

UncaughtException處理類(lèi)云头,當(dāng)程序發(fā)生Uncaught異常的時(shí)候,有該類(lèi)來(lái)接管程序淫半,并記錄發(fā)送錯(cuò)誤報(bào)告溃槐,我們可以實(shí)現(xiàn)UncaughtExceptionHandler類(lèi)的uncaughtException方法,該方法的參數(shù)為發(fā)生異常的線程和異常信息科吭,我們可以在該類(lèi)中自己處理異常昏滴,例如上報(bào)服務(wù)器或者記錄異常等,也可以交由系統(tǒng)的異常處理機(jī)制去處理对人。

示例代碼:

/**
* UncaughtException處理類(lèi),當(dāng)程序發(fā)生Uncaught異常的時(shí)候,有該類(lèi)來(lái)接管程序,并記錄發(fā)送錯(cuò)誤報(bào)告
*/
public class CrashHandler implements UncaughtExceptionHandler { 
//    public static final String TAG = "CrashHandler";
public static final String TAG = "liuyou";  
   //系統(tǒng)默認(rèn)的UncaughtException處理類(lèi) 
   private Thread.UncaughtExceptionHandler mDefaultHandler;
   //CrashHandler實(shí)例
   private static CrashHandler INSTANCE = new CrashHandler();
   //程序的Context對(duì)象
   private Context mContext;
   //用來(lái)存儲(chǔ)設(shè)備信息和異常信息
   private Map<String, String> infos = new HashMap<String, String>();
   //用于格式化日期,作為日志文件名的一部分
   private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
   /** 保證只有一個(gè)CrashHandler實(shí)例 */
   private CrashHandler() {
   }
   /** 獲取CrashHandler實(shí)例 ,單例模式 */
   public static CrashHandler getInstance() {
       return INSTANCE;
   }
   /**
    * 初始化
    * @param context
*/
   public void init(Context context) {
       mContext = context;
       //獲取系統(tǒng)默認(rèn)的UncaughtException處理器
       mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
       //設(shè)置該CrashHandler為程序的默認(rèn)處理器
       Thread.setDefaultUncaughtExceptionHandler(this);
   }
   /**
    * 當(dāng)UncaughtException發(fā)生時(shí)會(huì)轉(zhuǎn)入該函數(shù)來(lái)處理
*/
   @Override
   public void uncaughtException(Thread thread, Throwable ex) {
       if (!handleException(ex) && mDefaultHandler != null) {
           //如果用戶沒(méi)有處理則讓系統(tǒng)默認(rèn)的異常處理器來(lái)處理
           mDefaultHandler.uncaughtException(thread, ex);
       } else {
           try {
               Thread.sleep(3000);
           } catch (InterruptedException e) {
               Log.e(TAG, "error : ", e);
           }
           mDefaultHandler.uncaughtException(thread, ex);
           //退出程序
//            android.os.Process.killProcess(android.os.Process.myPid());
//            System.exit(1);
       }
   }
   /**
    * 自定義錯(cuò)誤處理,收集錯(cuò)誤信息 發(fā)送錯(cuò)誤報(bào)告等操作均在此完成.
    * @param ex
    * @return true:如果處理了該異常信息;否則返回false.
*/
   private boolean handleException(Throwable ex) {
       if (ex == null) {
           return false;
       }
       //使用Toast來(lái)顯示異常信息
       new Thread() {
           @Override
           public void run() {
               Looper.prepare();
//                Toast.makeText(mContext, "很抱歉,程序出現(xiàn)異常,即將退出.", Toast.LENGTH_LONG).show();
               Looper.loop();
           }
       }.start();
       //收集設(shè)備參數(shù)信息 
       collectDeviceInfo(mContext);
       //保存日志文件 
       Log.i("liuyou", "ex:"+ex.toString()+"--"+ex.getLocalizedMessage());
       saveCrashInfo2File(ex);
       return true;
   }
   /**
    * 收集設(shè)備參數(shù)信息
    * @param ctx
*/
   public void collectDeviceInfo(Context ctx) {
       try {
           PackageManager pm = ctx.getPackageManager();
           PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);
           if (pi != null) {
               String versionName = pi.versionName == null ? "null" : pi.versionName;
               String versionCode = pi.versionCode + "";
               infos.put("versionName", versionName);
               infos.put("versionCode", versionCode);
           }
       } catch (NameNotFoundException e) {
           Log.e(TAG, "an error occured when collect package info", e);
       }
       Field[] fields = Build.class.getDeclaredFields();
       for (Field field : fields) {
           try {
               field.setAccessible(true);
               infos.put(field.getName(), field.get(null).toString());
//                Log.d(TAG, field.getName() + " : " + field.get(null));
           } catch (Exception e) {
               Log.e(TAG, "an error occured when collect crash info", e);
           }
       }
   }
   /**
    * 保存錯(cuò)誤信息到文件中
    * @param ex
    * @return    返回文件名稱(chēng),便于將文件傳送到服務(wù)器
*/
   private String saveCrashInfo2File(Throwable ex) {       
       StringBuffer sb = new StringBuffer();
//        for (Map.Entry<String, String> entry : infos.entrySet()) {
//            String key = entry.getKey();
//            String value = entry.getValue();
//            sb.append(key + "=" + value + "\n");
//        }      
       Writer writer = new StringWriter();
       PrintWriter printWriter = new PrintWriter(writer);
       ex.printStackTrace(printWriter);
       Throwable cause = ex.getCause();
       while (cause != null) {
       Log.i("liuyou", "cause:"+cause.toString()+"--");
           cause.printStackTrace(printWriter);
           cause = cause.getCause();
       }
       printWriter.close();
       String result = writer.toString();
       Log.i("liuyou", "result:"+result);
       sb.append(result);
       try {
           long timestamp = System.currentTimeMillis();
           String time = formatter.format(new Date());
           String fileName = "crash-" + time + "-" + timestamp + ".log";
           if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
               String path = "/sdcard/crash/";
               File dir = new File(path);
               if (!dir.exists()) {
                   dir.mkdirs();
               }
               FileOutputStream fos = new FileOutputStream(path + fileName);
               fos.write(sb.toString().getBytes());
               fos.close();
           }
           return fileName;
       } catch (Exception e) {
           Log.e(TAG, "an error occured while writing file...", e);
       }
       return null;
   }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末谣殊,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子牺弄,更是在濱河造成了極大的恐慌蟹倾,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件猖闪,死亡現(xiàn)場(chǎng)離奇詭異鲜棠,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)培慌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)豁陆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人吵护,你說(shuō)我怎么就攤上這事盒音。” “怎么了馅而?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵祥诽,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我瓮恭,道長(zhǎng)雄坪,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任屯蹦,我火速辦了婚禮维哈,結(jié)果婚禮上绳姨,老公的妹妹穿的比我還像新娘。我一直安慰自己阔挠,他們只是感情好飘庄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著购撼,像睡著了一般跪削。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上迂求,一...
    開(kāi)封第一講書(shū)人閱讀 51,165評(píng)論 1 299
  • 那天碾盐,我揣著相機(jī)與錄音,去河邊找鬼锁摔。 笑死廓旬,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的谐腰。 我是一名探鬼主播孕豹,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼十气!你這毒婦竟也來(lái)了励背?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤砸西,失蹤者是張志新(化名)和其女友劉穎叶眉,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體芹枷,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡衅疙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鸳慈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饱溢。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖走芋,靈堂內(nèi)的尸體忽然破棺而出绩郎,到底是詐尸還是另有隱情,我是刑警寧澤翁逞,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布肋杖,位于F島的核電站,受9級(jí)特大地震影響挖函,放射性物質(zhì)發(fā)生泄漏状植。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望浅萧。 院中可真熱鬧逐沙,春花似錦哲思、人聲如沸洼畅。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)帝簇。三九已至,卻和暖如春靠益,著一層夾襖步出監(jiān)牢的瞬間丧肴,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工胧后, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留芋浮,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓壳快,卻偏偏與公主長(zhǎng)得像纸巷,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子眶痰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容