一個好的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 }