異常的體系
異常:是在運(yùn)行時(shí)期發(fā)生的不正常情況泼橘。 在java中用類(lèi)的形式對(duì)不正常情況進(jìn)行了描述和封裝對(duì)象涝动。描述不正常的情況的類(lèi),就稱(chēng)為異常類(lèi)炬灭。
- 以前正常流程代碼和問(wèn)題處理代碼相結(jié)合醋粟,現(xiàn)在將正常流程代碼和問(wèn)題處理代碼分離,提高閱讀性。
- 其實(shí)異常就是java通過(guò)面向?qū)ο蟮乃枷雽?wèn)題封裝成了對(duì)象米愿,用異常類(lèi)對(duì)其進(jìn)行描述厦凤。
- 不同的問(wèn)題用不同的類(lèi)進(jìn)行具體的描述。比如角標(biāo)越界育苟、空指針異常等等较鼓。
- 問(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ì)象都具備可拋性舆绎。
-
一般不可處理的:Error
特點(diǎn):是由jvm拋出的嚴(yán)重性問(wèn)題鲤脏。
這種問(wèn)題發(fā)生们颜,一般不針對(duì)性處理,直接修改程序猎醇。
-
可以處理的: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é)果:
自定義異常
可以自定義出現(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ū)別
throws用于標(biāo)識(shí)函數(shù)暴露出的異常類(lèi)丐怯,并且可以拋出多個(gè),用逗號(hào)分隔翔横。throw用于拋出異常對(duì)象
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é)果:
異常的分類(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é)果:
注意事項(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é)果:
異常處理的原則
函數(shù)內(nèi)容如果拋出需要檢測(cè)的異常磷蜀,那么函數(shù)上必須要聲明召耘。否則,必須在函數(shù)內(nèi)用try/catch捕捉褐隆,否則編譯失敗污它。
如果調(diào)用到了聲明異常的函數(shù),要么try/catch庶弃,要么throws衫贬,否則編譯失敗。
-
什么時(shí)候catch歇攻,什么時(shí)候throws呢固惯?
功能內(nèi)容可以解決,用catch缴守。解決不了缝呕,用throws告訴調(diào)用者,由調(diào)用者解決斧散。
一個(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é)果:
try catch finally 代碼塊組合特點(diǎn):
- try catch finally
- try catch(多個(gè)):當(dāng)沒(méi)有資源需要釋放時(shí),可以不用定義finally歇僧。
- 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é)果:
異常的注意事項(xiàng)
- RuntimeException以及其子類(lèi)如果在函數(shù)中被throw拋出疫萤,可以不用在函數(shù)上聲明趁矾。
- 子類(lèi)在覆蓋父類(lèi)方法時(shí),父類(lèi)的方法如果拋出了異常给僵,那么子類(lèi)的方法只能拋出父類(lèi)的異澈恋罚或者該異常的子類(lèi)。
- 如果父類(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;
}
}