Android 異常處理最佳實踐

希爾瓦娜斯女神發表於2015-12-10

一個好的app 異常處理機制 我認為應該至少包含以下幾個功能:

1.能把錯誤資訊上傳到伺服器  讓開發者可以持續改進app

2.錯誤資訊至少應該包含 是否在主程式 是否在主執行緒 等可以幫助程式設計師定位的資訊

3.最好包含手機硬體及軟體資訊。

4.主程式引發的異常 最好交由系統自己處理 也就是讓使用者可以感知到 那種(當然你也可以自己定義一套更有意思的感知系統對話方塊等,具體可參考各種有意思的404介面)

5.子程式引發的異常最好別讓使用者感知到。比如push之類的 這種 和使用者感知弱關聯的這種。最好發生異常就直接kill掉即可。不要再交給系統處理。

 

下面上程式碼。

 1 package com.example.administrator.exceptiontest;
 2 
 3 import android.app.ActivityManager;
 4 import android.app.Application;
 5 import android.content.Context;
 6 
 7 /**
 8  * Created by Administrator on 2015/12/9.
 9  */
10 public class BaseApplication extends Application {
11 
12     public static Context mContext;
13     //預設的異常處理
14     public static Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler;
15 
16     @Override
17     public void onCreate() {
18         super.onCreate();
19         mContext = this;
20         //先取得預設的異常處理handler
21         defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
22         Thread.setDefaultUncaughtExceptionHandler(new BaseUncaughtExceptionHandler());
23     }
24 
25 
26 }
 1 package com.example.administrator.exceptiontest;
 2 
 3 import android.app.ActivityManager;
 4 import android.content.Context;
 5 import android.os.Looper;
 6 
 7 /**
 8  * Created by Administrator on 2015/12/9.
 9  */
10 public class Utils {
11 
12     /**
13      * 判斷是否在主執行緒中執行 如果是返回true 不是返回false
14      */
15     public static boolean isInMainThread() {
16         //注意這個地方 我們無法一定可以取得myLooper的值的 比如說 你的thread 沒有繫結訊息迴圈
17         //那你的mylooper就返回的一定是null了,只有繫結了以後才會返回相應的值
18         return Looper.myLooper() == Looper.getMainLooper();
19     }
20 
21 
22     //判斷是否是主程式 如果是 就返回true 否則返回false
23     public static boolean isMainProcess(Context context)
24     {
25         return context.getPackageName().equals(getProcessName(context));
26     }
27 
28     //取得程式名
29     public static String getProcessName(Context context) {
30         String currentProcessName = "";
31         int pid = android.os.Process.myPid();
32         ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
33         for (ActivityManager.RunningAppProcessInfo processInfo : manager.getRunningAppProcesses()) {
34             if (processInfo.pid == pid) {
35                 currentProcessName = processInfo.processName;
36                 break;
37             }
38         }
39         return currentProcessName;
40     }
41 
42 }
 1 package com.example.administrator.exceptiontest;
 2 
 3 import java.io.PrintWriter;
 4 import java.io.StringWriter;
 5 import java.io.Writer;
 6 
 7 /**
 8  * Created by Administrator on 2015/12/9.
 9  */
10 public class BaseUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
11 
12     @Override
13     public void uncaughtException(Thread thread, Throwable ex) {
14         Writer resultWriter = new StringWriter();
15         PrintWriter printWriter = new PrintWriter(resultWriter);
16         ex.printStackTrace(printWriter);
17         StringBuffer sb = new StringBuffer();
18         sb.append("是否在主執行緒中發生異常" + Utils.isInMainThread() + "\n");
19         sb.append("是否在主程式中發生異常" + Utils.isMainProcess(BaseApplication.mContext) + "\n");
20         String errorReport = sb.toString() + resultWriter.toString();
21         //這個地方最好把收集到的錯誤資訊日誌 上傳至伺服器 便於開發者定位修改問題。
22         //如果是主程式發生了異常 那還是交給系統自己預設的異常處理來做。讓使用者感知到,否則使用者啥都不知道 體驗並不好
23         //你當然也可以自己定義特殊的錯誤提示 比如一些有意思的dialog什麼的
24         if (Utils.isMainProcess(BaseApplication.mContext)) {
25             BaseApplication.defaultUncaughtExceptionHandler.uncaughtException(thread, ex);
26         } else {
27             //如果是子程式發生異常 不要給提示 直接殺掉子程式最好 別讓使用者感知到
28             android.os.Process.killProcess(android.os.Process.myPid());
29         }
30     }
31 
32 
33 }

 

相關文章