標籤:android style blog java color 使用
眾所周知,android的裝置千差萬別,難免會發生崩潰異常等現象,這個時候就需要捕獲哪些崩潰異常了,也就是捕獲崩潰異常的相關資訊,並記錄下來,這樣一來方便開發人員和測試人員的分析與調試。
1.首先我們得建立一個處理崩潰異常的類,暫且命名為:CrashHandler吧。實現如下:
import java.io.File;import java.io.FileOutputStream;import java.io.PrintWriter;import java.io.StringWriter;import java.io.Writer;import java.lang.Thread.UncaughtExceptionHandler;import java.lang.reflect.Field;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Date;import java.util.HashMap;import java.util.Map;import java.util.TimeZone;import android.app.Activity;import android.app.AlertDialog;import android.content.Context;import android.content.DialogInterface;import android.content.DialogInterface.OnClickListener;import android.content.Intent;import android.content.pm.PackageInfo;import android.content.pm.PackageManager;import android.content.pm.PackageManager.NameNotFoundException;import android.os.Build;import android.os.Looper;import android.sax.StartElementListener;import android.util.Log;import android.widget.Toast;/** * UncaughtException處理類,當程式發生Uncaught異常的時候,有該類來接管程式,並記錄發送錯誤報表到log檔案中. * * @author caizhiming */public class CrashHandler implements UncaughtExceptionHandler { public static final String TAG = "CrashHandler"; // 系統預設的UncaughtException處理類 private Thread.UncaughtExceptionHandler mDefaultHandler; // CrashHandler執行個體 private static CrashHandler INSTANCE = new CrashHandler(); // 程式的Context對象 private Context mContext; // 用來存放裝置資訊和異常資訊 private Map<String, String> infos = new HashMap<String, String>(); // 用于格式化日期,作為記錄檔名的一部分 private SimpleDateFormat formatter; /** * 保證只有一個CrashHandler執行個體 */ private CrashHandler() { } /** * 擷取CrashHandler執行個體 ,單例模式 */ public static CrashHandler getInstance() { return INSTANCE; } /** * 初始化 * * @param context */ public void init(Context context) { mContext = context; // 擷取系統預設的UncaughtException處理器 mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); // 設定該CrashHandler為程式的預設處理器 Thread.setDefaultUncaughtExceptionHandler(this); } /** * 當UncaughtException發生時會轉入該函數來處理 */ @Override public void uncaughtException(Thread thread, Throwable ex) { if (!handleException(ex) && mDefaultHandler != null) { // 如果使用者沒有處理則讓系統預設的異常處理器來處理 mDefaultHandler.uncaughtException(thread, ex); } else { // 退出程式 try { Thread.sleep(300); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } android.os.Process.killProcess(android.os.Process.myPid()); System.exit(1); } } /** * 自訂錯誤處理,收集錯誤資訊 發送錯誤報表等操作均在此完成. * * @param ex * @return true:如果處理了該異常資訊;否則返回false. */ private boolean handleException(final Throwable ex) { if (ex == null) { return false; }// Intent showcrashDLg = new Intent(mContext,CrashActivity.class);// mContext.startActivity(showcrashDLg); ex.printStackTrace(); // 使用Toast來顯示異常資訊 // 收集裝置參數資訊 collectDeviceInfo(mContext); // 儲存記錄檔 saveCrashInfoToFile(ex); return true; } /** * 收集裝置參數資訊 * * @param ctx */ public void collectDeviceInfo(Context ctx) { try { PackageManager pm = ctx.getPackageManager(); PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES); if (pi != null) { String versionName = pi.versionName == null ? "null" : pi.versionName; String versionCode = pi.versionCode + ""; infos.put("versionName", versionName); infos.put("versionCode", versionCode); } } catch (NameNotFoundException e) { Log.e(TAG, "an error occured when collect package info", e); } Field[] fields = Build.class.getDeclaredFields(); for (Field field : fields) { try { field.setAccessible(true); infos.put(field.getName(), field.get(null).toString()); Log.d(TAG, field.getName() + " : " + field.get(null)); } catch (Exception e) { Log.e(TAG, "an error occured when collect crash info", e); } } } /** * 儲存錯誤資訊到檔案中 * * @param ex * @return 錯誤崩潰資訊寫到log檔案中 */ private void saveCrashInfoToFile(Throwable ex) { StringBuffer sb = new StringBuffer(); sb.append("==============================Crash happened at Time:" + CommonUtils.getCurTime() + "==============================\r\n"); for (Map.Entry<String, String> entry : infos.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); sb.append(key + "=" + value + "\r\n"); } 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(); sb.append(result); try { LogCore.addLog(sb.toString()); } catch (Exception e) { Log.e(TAG, "an error occured while writing file...", e); } Analyse.uplodcrash(sb.toString()); } /** * 用Dialog顯示錯誤資訊 * * @param ex * @return 用Dialog顯示錯誤資訊 */ private void showCrashInfoDialog(Throwable ex) { StringBuffer sb = new StringBuffer(); 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(); sb.append(result); try { // DlgUtils.ShowDialog(mContext,"程式崩潰了"); // LogCore.d(mContext,sb.toString()); AlertDialog.Builder builder = new AlertDialog.Builder(mContext); builder.setTitle("程式崩潰啦~"); builder.setMessage(sb.toString()); builder.setPositiveButton("我知道了", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub android.os.Process.killProcess(android.os.Process.myPid()); System.exit(1); } });// builder.create().show(); } catch (Exception e) { Log.e(TAG, "an error occured while writing file...", e); } }}
2.完成這個CrashHandler後,我們需要在一個Application環境中讓其運行,為此,我們繼承android.app.Application,添加自己的代碼,CrashApplication.java代碼如下:
package com.czm.crash; import android.app.Application; public class CrashApplication extends Application { @Override public void onCreate() { super.onCreate(); CrashHandler crashHandler = CrashHandler.getInstance(); crashHandler.init(getApplicationContext()); } }
3.除此之外,最後,為了讓上面的CrashApplication取代android.app.Application的地位,在我們的代碼中生效,我們需要修改AndroidManifest.xml:
<application android:name=".CrashApplication" ...> </application>