欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android崩潰異常捕獲方法

 更新時(shí)間:2016年03月23日 09:50:24   作者:jerrylsxu  
這篇文章主要介紹了Android崩潰異常捕獲方法的相關(guān)資料,需要的朋友可以參考下

開發(fā)中最讓人頭疼的是應(yīng)用突然爆炸,然后跳回到桌面。而且我們常常不知道這種狀況會(huì)何時(shí)出現(xiàn),在應(yīng)用調(diào)試階段還好,還可以通過調(diào)試工具的日志查看錯(cuò)誤出現(xiàn)在哪里。但平時(shí)使用的時(shí)候給你鬧崩潰,那你就欲哭無淚了。
那么今天主要講一下如何去捕捉系統(tǒng)出現(xiàn)的Unchecked異常。何為Unchecked異常呢,換句話說就是指非受檢異常,它不能用try-catch來顯示捕捉。

我們先從Exception講起。Exception分為兩類:一種是CheckedException,一種是UncheckedException。這兩種Exception的區(qū)別主要是CheckedException需要用try...catch...顯示的捕獲,而UncheckedException不需要捕獲。通常UncheckedException又叫做RuntimeException。《effective java》指出:對(duì)于可恢復(fù)的條件使用被檢查的異常(CheckedException),對(duì)于程序錯(cuò)誤(言外之意不可恢復(fù),大錯(cuò)已經(jīng)釀成)使用運(yùn)行時(shí)異常(RuntimeException)。我們常見的RuntimeExcepiton有IllegalArgumentException、IllegalStateException、NullPointerException、IndexOutOfBoundsException等等。對(duì)于那些CheckedException就不勝枚舉了,我們?cè)诰帉懗绦蜻^程中try...catch...捕捉的異常都是CheckedException。io包中的IOException及其子類,這些都是CheckedException。

一、使用UncaughtExceptionHandler來捕獲unchecked異常

UncaughtException處理類,當(dāng)程序發(fā)生Uncaught異常的時(shí)候,由該類來接管程序,并記錄發(fā)送錯(cuò)誤報(bào)告。
直接上代碼吧

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Environment;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
/**
* UncaughtException處理類,當(dāng)程序發(fā)生Uncaught異常的時(shí)候,有該類來接管程序,并記錄發(fā)送錯(cuò)誤報(bào)告.
* 
* @author user
* 
*/
@SuppressLint("SdCardPath")
public class CrashHandler implements UncaughtExceptionHandler {
public static final String TAG = "TEST";
// CrashHandler 實(shí)例
private static CrashHandler INSTANCE = new CrashHandler();
// 程序的 Context 對(duì)象
private Context mContext;
// 系統(tǒng)默認(rèn)的 UncaughtException 處理類
private Thread.UncaughtExceptionHandler mDefaultHandler;
// 用來存儲(chǔ)設(shè)備信息和異常信息
private Map<String, String> infos = new HashMap<String, String>();
// 用來顯示Toast中的信息
private static String error = "程序錯(cuò)誤,額,不對(duì),我應(yīng)該說,服務(wù)器正在維護(hù)中,請(qǐng)稍后再試";
private static final Map<String, String> regexMap = new HashMap<String, String>();
// 用于格式化日期,作為日志文件名的一部分
private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss",
Locale.CHINA);
/** 保證只有一個(gè) CrashHandler 實(shí)例 */
private CrashHandler() {
//
}
/** 獲取 CrashHandler 實(shí)例 ,單例模式 */
public static CrashHandler getInstance() {
initMap();
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);
Log.d("TEST", "Crash:init");
}
/**
* 當(dāng) UncaughtException 發(fā)生時(shí)會(huì)轉(zhuǎn)入該函數(shù)來處理
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
// 如果用戶沒有處理則讓系統(tǒng)默認(rèn)的異常處理器來處理
mDefaultHandler.uncaughtException(thread, ex);
Log.d("TEST", "defalut");
} else {
try {
Thread.sleep();
} catch (InterruptedException e) {
Log.e(TAG, "error : ", e);
}
// 退出程序
android.os.Process.killProcess(android.os.Process.myPid());
// mDefaultHandler.uncaughtException(thread, ex);
System.exit();
}
}
/**
* 自定義錯(cuò)誤處理,收集錯(cuò)誤信息,發(fā)送錯(cuò)誤報(bào)告等操作均在此完成
* 
* @param ex
* @return true:如果處理了該異常信息;否則返回 false
*/
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}
// 收集設(shè)備參數(shù)信息
// collectDeviceInfo(mContext);
// 保存日志文件
saveCrashInfoFile(ex);
// 使用 Toast 來顯示異常信息
new Thread() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(mContext, error, Toast.LENGTH_LONG).show();
Looper.loop();
}
}.start();
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 返回文件名稱,便于將文件傳送到服務(wù)器
*/
private String saveCrashInfoFile(Throwable ex) {
StringBuffer sb = getTraceInfo(ex);
Writer writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
ex.printStackTrace(printWriter);
Throwable cause = ex.getCause();
while (cause != null) {
cause.printStackTrace(printWriter);
cause = cause.getCause();
}
printWriter.close();
String result = writer.toString();
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 = Environment.getExternalStorageDirectory()
+ "/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;
}
/**
* 整理異常信息
* @param e
* @return
*/
public static StringBuffer getTraceInfo(Throwable e) {
StringBuffer sb = new StringBuffer();
Throwable ex = e.getCause() == null ? e : e.getCause();
StackTraceElement[] stacks = ex.getStackTrace();
for (int i = ; i < stacks.length; i++) {
if (i == ) {
setError(ex.toString());
}
sb.append("class: ").append(stacks[i].getClassName())
.append("; method: ").append(stacks[i].getMethodName())
.append("; line: ").append(stacks[i].getLineNumber())
.append("; Exception: ").append(ex.toString() + "\n");
}
Log.d(TAG, sb.toString());
return sb;
}
/**
* 設(shè)置錯(cuò)誤的提示語(yǔ)
* @param e
*/
public static void setError(String e) {
Pattern pattern;
Matcher matcher;
for (Entry<String, String> m : regexMap.entrySet()) {
Log.d(TAG, e+"key:" + m.getKey() + "; value:" + m.getValue());
pattern = Pattern.compile(m.getKey());
matcher = pattern.matcher(e);
if(matcher.matches()){
error = m.getValue();
break;
}
}
}
/**
* 初始化錯(cuò)誤的提示語(yǔ)
*/
private static void initMap() {
// Java.lang.NullPointerException
// java.lang.ClassNotFoundException
// java.lang.ArithmeticException
// java.lang.ArrayIndexOutOfBoundsException
// java.lang.IllegalArgumentException
// java.lang.IllegalAccessException
// SecturityException
// NumberFormatException
// OutOfMemoryError 
// StackOverflowError 
// RuntimeException 
regexMap.put(".*NullPointerException.*", "嘿,無中生有~Boom!");
regexMap.put(".*ClassNotFoundException.*", "你確定你能找得到它?");
regexMap.put(".*ArithmeticException.*", "我猜你的數(shù)學(xué)是體育老師教的,對(duì)吧?");
regexMap.put(".*ArrayIndexOutOfBoundsException.*", "恩,無下限=無節(jié)操,請(qǐng)不要跟我搭話");
regexMap.put(".*IllegalArgumentException.*", "你的出生就是一場(chǎng)錯(cuò)誤。");
regexMap.put(".*IllegalAccessException.*", "很遺憾,你的信用卡賬號(hào)被凍結(jié)了,無權(quán)支付");
regexMap.put(".*SecturityException.*", "死神馬上降臨");
regexMap.put(".*NumberFormatException.*", "想要改變一下自己形象?去泰國(guó)吧,包你滿意");
regexMap.put(".*OutOfMemoryError.*", "或許你該減減肥了");
regexMap.put(".*StackOverflowError.*", "啊,啊,憋不住了!");
regexMap.put(".*RuntimeException.*", "你的人生走錯(cuò)了方向,重來吧");
}
}

二、建立一個(gè)Application來全局監(jiān)控

import android.app.Application;
public class CrashApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
CrashHandler crashHandler = CrashHandler.getInstance();
crashHandler.init(getApplicationContext());
}
} 

最后在配置文件中加入注冊(cè)信息

<application android:name=".CrashApplication" ... /> 

和權(quán)限

<!--uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 

提交錯(cuò)誤日志到網(wǎng)絡(luò)服務(wù)器這一塊還沒有添加。如果添加了這一塊功能,就能夠?qū)崟r(shí)的得要用戶使用時(shí)的錯(cuò)誤日志,能夠及時(shí)反饋不同機(jī)型不同時(shí)候發(fā)生的錯(cuò)誤,能對(duì)我們開發(fā)者的后期維護(hù)帶來極大的方便。

有關(guān)Android崩潰異常捕獲方法小編就給大家介紹這么多,希望對(duì)大家有所幫助!

相關(guān)文章

最新評(píng)論