Android進階;App的異常崩潰處理
做任何軟體,都需要考慮異常情況的處理,這是軟體的可維護性的一部分。
異常崩潰是一種罕見的極端異常情況,這種情況下,針對終端使用者的UI反饋、事故裝置的資訊採集、向後臺維護人員的資料反饋等,都需要精心的設計。
UI反饋
- 要做反饋,首先要抓到所有的異常崩潰。
異常崩潰都是App程式的異常,每個App程式都執行在該App的Application中,所以我們可以在Application上集中抓到所有的程式異常:
private Thread.UncaughtExceptionHandler uncaughtExceptionHandler;
private Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() {
if (uncaughtExceptionHandler == null) {
uncaughtExceptionHandler = CrashHandler.getInstance(this,this);
}
return uncaughtExceptionHandler;
}
private void init(){
Thread.setDefaultUncaughtExceptionHandler(getUncaughtExceptionHandler());
}
我們抓到所有的程式異常,然後統一拋給一個CrashHandler類去處理,這個CrashHandler要實現UncaughtExceptionHandler介面:
public class CrashHandler implements UncaughtExceptionHandler{
@Override
public void uncaughtException(Thread thread, Throwable ex) {
}
}
- 盡力保持使用者資料的完整性,並設法恢復崩潰前的介面。
如果要在崩潰時重啟App,就需要在退出App前,再次StartActivity
Intent i = mContext.getPackageManager().getLaunchIntentForPackage(mContext.getPackageName());
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
mContext.startActivity(i);
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
其中,android.os.Process.killProcess(Dalvik虛擬機器方法)和System.exit(0)(常規java方法)起到的作用一樣。
這裡有一個關於Activity棧的陷阱,上面的程式碼可以重啟入口Activity,但是,如果這時你這個App的Activity棧裡還有其他的Activity,這些Activity是仍然存在的,不會被銷燬。
推薦的做法是在Application中維護一個Activity的列表,專門管理所有的Activity,在必要時,通過這個列表,去銷燬所有的Activity
private ActivityStack stack;//擴充套件LinkList自定義一個activity列表
//用set注入
@Override
public void initActivityStack(ActivityStack stack) {
this.stack=stack;
}
//activity在oncreate時做新增//
@Override
public void addActivity(Activity activity) {
if(stack!=null)stack.addStack(activity);
}
//activity在ondestroy時做刪減//
@Override
public void removeActivity(Activity activity) {
if(stack!=null)stack.remove(activity);
}
@Override
public void clearAll() {
if(stack!=null)stack.clearAll();
}
在這個自定義的activity列表裡,通過呼叫Activity的finish,來銷燬Activity
public void clearAll() {
if(stack!=null&&stack.size()>0) {
for (Activity activity : stack) {
if (activity != null) {
activity.finish();
}
}
stack.clear();
}
}
注意,為了避免Application持有Activity導致記憶體洩露,在Activity的生命週期裡不能只寫入列,還要記得寫出列。
- 然後要提示使用者發生了一些事情,這裡要謹慎措辭,最好根據產品特性設計一些符合產品氣質的提示語,這裡就不展開了。
- 最後,在自動重啟和退出App之間尋找平衡,比如第一次崩潰當然可以自動重啟,如果遇到特殊因素導致連續崩潰(如:介面問題或執行環境問題),就需要人為限制重啟的次數或頻率(比如,記錄上次自動重啟的時間,判斷兩次重啟的時間間隔是否過窄),避免成為使用者眼中的流氓軟體。
資訊採集
對異常崩潰瞭解的越多,就越容易處理它,所以我們要儘可能地採集相關資訊。
對研發來說,最有用的當然是異常程式碼行(如MainActivity第61行)和異常原因(如空指標異常),在研發環境裡,我們可以通過logcat讀到這些資訊,那沒什麼可說的,我們要考慮的是,如果異常崩潰發生在萬里之外的生產環境,我們要怎樣採集資訊。
- 首先,要建立和儲存本地log資料夾,專門儲存這些資訊,一方面,網路不是一直可靠的,儲存到本地可以避免資料丟失;另一方面,無論是遠端資料上傳還是現場同僚手動拷貝,都需要有這樣一個資料夾。
- 然後,要抓取異常程式碼行和異常原因,也就是你在logcat裡讀到的那些異常堆疊資訊,所有的Java異常都會丟擲一個Throwable,這裡面就能找到這些異常堆疊資訊(需要用printwriter去讀)
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();
- 最後,有些崩潰是在特定的軟硬體環境下出現的,我們需要知道這些環境資訊:
Map<String, String> infos = new HashMap<String, String>();
Field[] fields = Build.class.getDeclaredFields();
for (Field field : fields) {
try {
field.setAccessible(true);
infos.put(field.getName(), field.get(null).toString());
} catch (Exception e) {
Log.e(TAG, "an error occured when collect crash info", e);
}
}
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");
}
資料反饋
首選當然是通過後臺網路默默反饋(在WIFI環境下,避免消耗使用者流量)。
如果是以檔案為單位上傳反饋,只要做好鎖檔案和銷燬檔案即可。
如果是線上實時上傳反饋,就需要為每次崩潰編號,或根據編號依次上傳,或在後臺進行合併過濾。
需要注意的是,本地日誌檔案不能過大,如果超過一定大小限制,要有自動清理機制,比如刪除日期最早的那個檔案,是的,強烈建議根據日期來建立多個日誌檔案。
附錄;
附錄二;Android進階實戰技術視訊
獲取方式;
加Android進階群;701740775。即可前往免費領取。免費備註一下csdn
相關文章
- Android 收集程式崩潰異常資訊Android
- Java進階02 異常處理Java
- Python進階08 異常處理Python
- Spring進階之@ControllerAdvice與統一異常處理SpringController
- CrashSight異常崩潰管理解決方案
- app 崩潰的原因APP
- APP防崩潰APP
- 異常的處理
- 異常-throws的方式處理異常
- 異常篇——異常處理
- 異常處理
- Flutter異常捕獲和Crash崩潰日誌收集Flutter
- A站大流量導致服務崩潰異常分析
- JSP 異常處理如何處理?JS
- Java 異常進階Java
- React 異常處理React
- JS異常處理JS
- oracle異常處理Oracle
- Python——異常處理Python
- Python異常處理Python
- ThinkPHP 異常處理PHP
- JavaScript 異常處理JavaScript
- JAVA 異常處理Java
- golang - 異常處理Golang
- 異常處理2
- 異常處理1
- Java 異常處理Java
- Abp 異常處理
- JAVA異常處理Java
- 08、異常處理
- SpringMVC異常處理SpringMVC
- 移動App測試崩潰常見的測試場景APP
- SpringBoot進行優雅的全域性異常處理Spring Boot
- 異常處理機制(二)之異常處理與捕獲
- VC++ 崩潰處理以及列印呼叫堆疊C++
- 異常-try...catch的方式處理異常1
- 異常-try...catch的方式處理異常2
- 「Go框架」gin框架是如何做崩潰處理的?Go框架