Android全局捕獲異常

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;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末饮怯,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子嚎研,更是在濱河造成了極大的恐慌蓖墅,老刑警劉巖库倘,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異论矾,居然都是意外死亡教翩,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門贪壳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來饱亿,“玉大人,你說我怎么就攤上這事闰靴”肓” “怎么了?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵蚂且,是天一觀的道長配猫。 經(jīng)常有香客問我,道長杏死,這世上最難降的妖魔是什么泵肄? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮识埋,結(jié)果婚禮上凡伊,老公的妹妹穿的比我還像新娘。我一直安慰自己窒舟,他們只是感情好系忙,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著惠豺,像睡著了一般银还。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上洁墙,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天蛹疯,我揣著相機與錄音,去河邊找鬼热监。 笑死捺弦,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的孝扛。 我是一名探鬼主播列吼,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼苦始!你這毒婦竟也來了寞钥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤陌选,失蹤者是張志新(化名)和其女友劉穎理郑,沒想到半個月后蹄溉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡您炉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年柒爵,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赚爵。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡餐弱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出囱晴,到底是詐尸還是另有隱情,我是刑警寧澤瓢谢,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布畸写,位于F島的核電站,受9級特大地震影響氓扛,放射性物質(zhì)發(fā)生泄漏枯芬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一采郎、第九天 我趴在偏房一處隱蔽的房頂上張望千所。 院中可真熱鬧,春花似錦蒜埋、人聲如沸淫痰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽待错。三九已至,卻和暖如春烈评,著一層夾襖步出監(jiān)牢的瞬間火俄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工讲冠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留瓜客,地道東北人。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓竿开,卻偏偏與公主長得像谱仪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子德迹,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

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