Android 收集程式崩潰異常資訊
前言
在日常開發中,如果遇到Android程式崩潰,我們只需要開啟AndroidStudio的控制檯的Logcat便能檢視到程式的崩潰資訊。
可是當程式上線後,如果出現程式崩潰的情況,我們可能很難找到問題。這就需要我們的程式能夠自己收集到崩潰的異常資訊,然後再適當的時候將這些資訊上傳到伺服器,然後我們獲取到這些異常資訊後,在下個更新的版本將其修復。
思路
- Android使用Thread.UncaughtExceptionHandler介面類來處理程式崩潰的情況,我們也可以通過該介面實現程式崩潰時的資訊收集等操作。
- 單例模式實現,初始化獲取系統預設的UncaughtException處理器,可以將部分操作交給預設處理器處理,然後設定CrashHandler為程式的預設處理器。
- 實現介面方法uncaughtException(Thread thread, Throwable ex),收集程式,裝置,崩潰異常等資訊。收集完資訊後,交給系統自己處理。
- 為方便檢視,收集的資訊儲存到txt檔案中,預設儲存在sd卡根目錄/你的app_name/Crash/ (如:
/storage/emulated/0/ErrorCatch/Crash/2018-09-21 09:42:59.text
) - getCrashReportFiles(Context ctx)方法可以返回所有的錯誤資訊檔案路徑,可以根據檔案路徑上傳到伺服器,然後將其刪除,防止重複上傳。
程式碼&Demo
GitHub:https://github.com/DeMonLiu623/CrashHandler
效果
在Demo中我們模擬實現了一個陣列越界異常,收集到的異常資訊如下圖:
實現
程式碼很簡單,而且註釋很詳細。
public class CrashHandler implements Thread.UncaughtExceptionHandler {
private static final String TAG = "CrashHandler";
/**
* 系統預設的UncaughtException處理類
*/
private Thread.UncaughtExceptionHandler mDefaultHandler;
/**
* 程式的Context物件
*/
private Context mContext;
/**
* 錯誤報告檔案的副檔名
*/
private static final String CRASH_REPORTER_EXTENSION = ".text";
/**
* CrashHandler例項
*/
private static CrashHandler INSTANCE;
/**
* 保證只有一個CrashHandler例項
*/
private CrashHandler() {
}
/**
* 獲取CrashHandler例項 ,單例模式
*/
public static CrashHandler getInstance() {
if (INSTANCE == null) {
synchronized (CrashHandler.class) {
if (INSTANCE == null) {
INSTANCE = new CrashHandler();
}
}
}
return INSTANCE;
}
/**
* 初始化,註冊Context物件,
* 獲取系統預設的UncaughtException處理器,可以將部分操作交給預設處理器處理
* 設定該CrashHandler為程式的預設處理器
*
* @param ctx
*/
public void init(Context ctx) {
mContext = ctx;
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
}
/**
* 當UncaughtException發生時會轉入該函式來處理
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
handleException(ex);
if (mDefaultHandler != null) {
//收集完資訊後,交給系統自己處理崩潰
mDefaultHandler.uncaughtException(thread, ex);
}
}
/**
* 自定義錯誤處理,收集錯誤資訊
* 傳送錯誤報告等操作均在此完成.
* 開發者可以根據自己的情況來自定義異常處理邏輯
*/
private void handleException(Throwable ex) {
if (ex == null) {
Log.w(TAG, "handleException--- ex==null");
return;
}
String msg = ex.getLocalizedMessage();
if (msg == null) {
return;
}
//收集裝置資訊
//儲存錯誤報告檔案
saveCrashInfoToFile(ex);
}
/**
* 獲取錯誤報告檔案路徑
*
* @param ctx
* @return
*/
public static String[] getCrashReportFiles(Context ctx) {
File filesDir = new File(getCrashFilePath(ctx));
String[] fileNames = filesDir.list();
int length = fileNames.length;
String[] filePaths = new String[length];
for (int i = 0; i < length; i++) {
filePaths[i] = getCrashFilePath(ctx) + fileNames[i];
}
return filePaths;
}
/**
* 儲存錯誤資訊到檔案中
*
* @param ex
* @return
*/
private void saveCrashInfoToFile(Throwable ex) {
Writer info = new StringWriter();
PrintWriter printWriter = new PrintWriter(info);
ex.printStackTrace(printWriter);
Throwable cause = ex.getCause();
while (cause != null) {
cause.printStackTrace(printWriter);
cause = cause.getCause();
}
String result = info.toString();
printWriter.close();
StringBuilder sb = new StringBuilder();
@SuppressLint("SimpleDateFormat") SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
String now = sdf.format(new Date());
sb.append("TIME:").append(now);//崩潰時間
//程式資訊
sb.append("\nAPPLICATION_ID:").append(BuildConfig.APPLICATION_ID);//軟體APPLICATION_ID
sb.append("\nVERSION_CODE:").append(BuildConfig.VERSION_CODE);//軟體版本號
sb.append("\nVERSION_NAME:").append(BuildConfig.VERSION_NAME);//VERSION_NAME
sb.append("\nBUILD_TYPE:").append(BuildConfig.BUILD_TYPE);//是否是DEBUG版本
//裝置資訊
sb.append("\nMODEL:").append(android.os.Build.MODEL);
sb.append("\nRELEASE:").append(Build.VERSION.RELEASE);
sb.append("\nSDK:").append(Build.VERSION.SDK_INT);
sb.append("\nEXCEPTION:").append(ex.getLocalizedMessage());
sb.append("\nSTACK_TRACE:").append(result);
try {
FileWriter writer = new FileWriter(getCrashFilePath(mContext) + now + CRASH_REPORTER_EXTENSION);
writer.write(sb.toString());
writer.flush();
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 獲取資料夾路徑
*
* @param context
* @return
*/
private static String getCrashFilePath(Context context) {
String path = null;
try {
path = Environment.getExternalStorageDirectory().getCanonicalPath() + "/" + context.getResources().getString(R.string.app_name) + "/Crash/";
File file = new File(path);
if (!file.exists()) {
file.mkdirs();
}
} catch (IOException e) {
e.printStackTrace();
}
return path;
}
}
相關文章
- Flutter異常捕獲和Crash崩潰日誌收集Flutter
- Android進階;App的異常崩潰處理AndroidAPP
- 簡便地Android崩潰日誌收集Android
- CrashSight異常崩潰管理解決方案
- A站大流量導致服務崩潰異常分析
- 小程式異常監控收集
- iOS 避免常見崩潰(二)iOS
- iOS 避免常見崩潰(一)iOS
- Android | 零程式碼快速整合AGC崩潰服務AndroidGC
- 記一次 .NET 某教育系統API 異常崩潰分析API
- Android 12 “致命”崩潰解決之路Android
- Android 崩潰日誌採集元件-DhccCrashLibAndroid元件
- Android7.1.1Toast崩潰解決方案AndroidAST
- 兩種異常(CPU異常、使用者模擬異常)的收集
- UE4 記憶體寫壞導致異常崩潰問題記錄記憶體
- AI|經常崩潰的問題解決AI
- WWDC 2018:理解崩潰以及崩潰日誌
- Mac騰訊截圖閃退崩潰Mac
- MySQL 資料庫崩潰(crash)的常見原因和解決辦法MySql資料庫
- 【伺服器資料恢復】多次異常斷電後儲存執行中突然崩潰的資料恢復伺服器資料恢復
- win10資源管理器經常崩潰怎麼辦 win10資源管理器不停的崩潰修復方法Win10
- win10經常網頁崩潰怎麼解決 win10網頁崩潰如何修復Win10網頁
- 崩潰日記
- APP防崩潰APP
- 儲存過程——異常捕獲&列印異常資訊儲存過程
- 360瀏覽器總是崩潰是為什麼 360瀏覽器經常崩潰怎麼解決瀏覽器
- 360瀏覽器總是崩潰是為什麼 360經常崩潰解決修復方法介紹瀏覽器
- Android 高質量開發之崩潰最佳化Android
- win10 qq視訊崩潰怎麼修復_win10系統qq視訊老是崩潰解決方法Win10
- w10玩lol經常崩潰怎麼辦_w10玩英雄聯盟崩潰的解決方法
- Go程式崩潰現場應該如何保留?Go
- C++記錄程式崩潰時的dumpfileC++
- app 崩潰的原因APP
- iOS Crash不崩潰iOS
- 異常錯誤資訊處理
- 應用崩潰了?Android vitals 幫您精確診斷應用崩潰Android
- 執行緒崩潰為什麼不會導致 JVM 崩潰執行緒JVM
- win10系統驅動崩潰怎麼辦_win10系統驅動經常崩潰解決方法Win10