[Android]Android apk崩潰捕獲異常儲存到本地(捕獲執行緒異常)
阿新 • • 發佈:2019-02-16
前段時間又溫習了下Java,發現了一隻野生的UncaughtExceptionHandler,以前居然沒發現
從JDK1.5版本開始,加強了對執行緒的異常處理,如果執行緒沒有捕獲異常,那麼Java虛擬機器會尋找相關的UncaughtExceptionHandler例項,如果找到就呼叫它的uncaughtException(Thread t, Throwable e)方法。
在Thread類中提供了一個公共的靜態的UncaughtExceptionHandler內部介面,負責處理執行緒未捕獲的異常,它的唯一方法是uncaughtException(Thread t, Throwable e),t表示丟擲異常的執行緒,e表示具體的異常。
Thread類提供兩個設定異常處理類的方法:
setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler e)
第一個方法是靜態方法,設定執行緒類的預設異常處理器,第二個是例項方法,設定執行緒例項的當前異常處理器;
Android中如果要把日誌寫到SD卡中記得加android.permission.WRITE_EXTERNAL_STORAGE許可權
要在application裡初始化
CrashHandler handler = CrashHandler.getInstance();
handler.init(this);
程式碼:
package com.peak.excatch; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.lang.Thread.UncaughtExceptionHandler; import java.text.SimpleDateFormat; import java.util.Date; 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.util.Log; public class CrashHandler implements UncaughtExceptionHandler { private static final String TAG = "CrashHandler"; private static final boolean DEBUG = true; private static final String PATH = Environment.getExternalStorageDirectory().getPath()+"/exceptionCatch/log/"; private static final String FILE_NAME = "catch"; private static final String FLIE_NAME_SUFFIX = ".log"; private UncaughtExceptionHandler mDefaultCrashHandler; private Context mContext; public CrashHandler() { } /** * 靜態內部類單例 * @return */ public static CrashHandler getInstance(){ Log.d(TAG, "get crash instance."); return InstanceHolder.sInstance; } private static class InstanceHolder{ private static CrashHandler sInstance = new CrashHandler(); } public void init(Context context){ Log.d(TAG, "init UncaughtExceptionnHandler"); mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler(this); mContext = context.getApplicationContext(); } /** * 程式崩潰會呼叫該方法 */ @Override public void uncaughtException(Thread thread, Throwable ex) { try{ Log.d(TAG, "uncaughtException ..."); dumpExceptionToSDCard(ex); // uploadExceptionToServer(ex); 需要把異常上傳到伺服器,編寫邏輯 解除該行註釋 }catch(IOException e){ e.printStackTrace(); } } private void dumpExceptionToSDCard(final Throwable ex) throws IOException{ if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ if(DEBUG){ Log.w(TAG, "sdcard unmounted,skip dump exception"); return; } } File dir = new File(PATH); if(!dir.exists()){ Log.d(TAG, "log dir not exists. ready create"); dir.mkdirs(); } long current = System.currentTimeMillis(); final String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(current)); final File file = new File(PATH + FILE_NAME + FLIE_NAME_SUFFIX); new Thread(new Runnable() { @Override public void run() { try{ PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file))); pw.println(time); dumpPhoneInfo(pw,ex); pw.close(); }catch(Exception e){ Log.e(TAG, "dump crash info failed : " + Log.getStackTraceString(e)); } } }).start(); } private void dumpPhoneInfo(PrintWriter pw, Throwable ex)throws NameNotFoundException { Log.d(TAG, "dumpPhoneInfo ... start"); PackageManager pm = mContext.getPackageManager(); PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(),PackageManager.GET_ACTIVITIES); pw.print("App version: "); pw.print(pi.versionName); pw.print('_'); pw.println(pi.versionCode); //Android版本號 pw.print("OS Version: "); pw.print(Build.VERSION.RELEASE); pw.print(" _ sdk: "); pw.println(Build.VERSION.SDK_INT); //手機制造商 pw.print("Vendor: "); pw.println(Build.MANUFACTURER); //手機型號 pw.print("Model: "); pw.println(Build.MODEL); //CPU架構 pw.print("CPU ABI : "); pw.println(Build.CPU_ABI); pw.println(); //異常資訊 ex.printStackTrace(pw); } private void uploadExceptionToServer(Throwable ex){ //上傳到伺服器邏輯程式碼 } }