import android.content.Context;
import android.content.Intent;
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;
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;
mport java.util.HashMap;
import java.util.Map;
/** * Created by TF on 2017/1/6. */
public class CrashHandlerUtil implements UncaughtExceptionHandler
{
public static final String TAG = "CrashHandlerUtil";
// CrashHandler 實例
private static CrashHandlerUtil INSTANCE = new CrashHandlerUtil();
// 程序的 Context 對象
private Context mContext;
// 系統(tǒng)默認的 UncaughtException 處理類
private Thread.UncaughtExceptionHandler mDefaultHandler;
// 用來存儲設(shè)備信息和異常信息
private Map<String, String> infos = new HashMap<String, String>();
// 用于格式化日期,作為日志文件名的一部分
private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
/**
* 保證只有一個 CrashHandler 實例
*/
private CrashHandlerUtil() {
}
/**
* 獲取 CrashHandler 實例 ,單例模式
*/
public static CrashHandlerUtil getInstance() {
return INSTANCE;
}
/**
* 初始化
*
* @param context
*/
public void init(Context context) {
mContext = context;
// 獲取系統(tǒng)默認的 UncaughtException 處理器
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
// 設(shè)置該 CrashHandler 為程序的默認處理器
Thread.setDefaultUncaughtExceptionHandler(this);
}
/**
* 當 UncaughtException 發(fā)生時會轉(zhuǎn)入該函數(shù)來處理
*/
@Override public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
// 如果用戶沒有處理則讓系統(tǒng)默認的異常處理器來處理
mDefaultHandler.uncaughtException(thread, ex);
} else {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
Log.e(TAG, "error : ", e);
}
// 退出程序,注釋下面的重啟啟動程序代碼
// android.os.Process.killProcess(android.os.Process.myPid());
// System.exit(1);
// 重新啟動程序够吩,注釋上面的退出程序
Intent intent = new Intent();
intent.setClass(mContext, StartActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK |
Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
android.os.Process.killProcess(android.os.Process.myPid());
}
}
/**
* 自定義錯誤處理比然,收集錯誤信息,發(fā)送錯誤報告等操作均在此完成
*
* @param ex
* @return true:如果處理了該異常信息周循;否則返回 false
*/
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}
// 使用 Toast 來顯示異常信息
new Thread() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(mContext, "很抱歉强法,程序出現(xiàn)異常,即將重啟湾笛。", Toast.LENGTH_LONG).show();
Looper.loop();
}
}.start();
// 收集設(shè)備參數(shù)信息
collectDeviceInfo(mContext);
// 保存日志文件
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);
}
}
}
/**
* 保存錯誤信息到文件中
* ?*
*
* @param ex
* @return 返回文件名稱, 便于將文件傳送到服務(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) {
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 = "/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;
}
}
Android全局捕獲異常
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
- 文/潘曉璐 我一進店門贪壳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來饱亿,“玉大人,你說我怎么就攤上這事闰靴”肓” “怎么了?”我有些...
- 文/不壞的土叔 我叫張陵蚂且,是天一觀的道長配猫。 經(jīng)常有香客問我,道長杏死,這世上最難降的妖魔是什么泵肄? 我笑而不...
- 正文 為了忘掉前任,我火速辦了婚禮识埋,結(jié)果婚禮上凡伊,老公的妹妹穿的比我還像新娘。我一直安慰自己窒舟,他們只是感情好系忙,可當我...
- 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著惠豺,像睡著了一般银还。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上洁墙,一...
- 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼苦始!你這毒婦竟也來了寞钥?” 一聲冷哼從身側(cè)響起,我...
- 正文 年R本政府宣布畸写,位于F島的核電站,受9級特大地震影響氓扛,放射性物質(zhì)發(fā)生泄漏枯芬。R本人自食惡果不足惜,卻給世界環(huán)境...
- 文/蒙蒙 一采郎、第九天 我趴在偏房一處隱蔽的房頂上張望千所。 院中可真熱鬧,春花似錦蒜埋、人聲如沸淫痰。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽待错。三九已至,卻和暖如春烈评,著一層夾襖步出監(jiān)牢的瞬間火俄,已是汗流浹背。 一陣腳步聲響...
推薦閱讀更多精彩內(nèi)容
- 應(yīng)用的crash是讓人很蛋疼的問題芽卿,在開發(fā)測試的時候還能根據(jù)日志輸出什么的進行排查修復(fù),但是應(yīng)用發(fā)布以后胳搞,用戶的隨...
- 眾所周知卸例,Android程序在運行時遇到未處理的錯誤,會彈出類似程序異常退出之類的dialog,然后自動關(guān)閉称杨。那么...
- 大家都知道,現(xiàn)在安裝Android系統(tǒng)的手機版本和設(shè)備千差萬別筷转,在模擬器和自己的android手機上運行良好的程序...
- 用三年的時間去明白一個道理 我的眼睛濕潤了 滾燙的熱淚滑過臉頰 透過車窗 我深深地看清了曾經(jīng)那個卑微的自己 相愛 ...