在Android手機上保存Crash Log

  1. 定義CrashLog文件:若是有存儲器,則將文件保存在存儲器下。不然保存在data目錄下。存儲器不必定是SD卡,也多是mount出來的一塊存儲空間(不是內存)。好比,小米3就沒有SD卡。java

    public class CrashLog {
     private static Context mContext;
     public static final String DIR_FOR_APP = "myApp";
     public static final String FILE_NAME_FOR_CRASH__LOG = "crash.txt";
     
     public static void setContext( Context aContext ) {
      mContext = aContext.getApplicationContext();
     }
     
     public static void writeLog(String log) throws Exception {
      File dir = createFileDir(DIR_FOR_APP);
      File file = new File(dir.getPath(), FILE_NAME_FOR_CRASH__LOG);
      if(!file.exists()){
       file.createNewFile();
      }
      StringBuffer orgStr = new StringBuffer();
      FileReader fr = new FileReader(file);
      int ch = 0;
      while((ch = fr.read()) != -1) {  
       orgStr.append((char)ch);
      }
      fr.close();
      
      Calendar c = Calendar.getInstance();
      String time = String.format("%2d:", c.get(Calendar.HOUR))+
      String.format("%2d:", c.get(Calendar.MINUTE))+
      String.format("%2d", c.get(Calendar.SECOND))+" ";
      String str = orgStr.toString() + "\r\n" + time + log + "\r\n";
      FileWriter fw = new FileWriter(file);
      fw.write(str);
      fw.close();
     }
     
     public static void clearLog(){
      String dirPath = getDirPath(DIR_FOR_APP);
      if( dirPath != null ) {
       File file = new File(FILE_NAME_FOR_CRASH__LOG);
       if(file.exists()){
        file.delete();
       }
      }
     }
     
      public static String getDirPath(String dirName){
       String filePath = null;
       String state = Environment.getExternalStorageState();
       if (state.equals(Environment.MEDIA_MOUNTED)) {
        // 若是有存儲器,則返回存儲器的路徑
        filePath = Environment.getExternalStorageDirectory()
          + File.separator + dirName;
       } else {// 不然返回data目錄的路徑
        filePath = mContext.getCacheDir().getPath() + File.separator
          + dirName;
       }
       return filePath;
      }
         
      public static File createFileDir(String dirName) {
       String filePath = getDirPath(dirName);
       if( filePath == null ) {
        return null;
       }
       File destDir = new File(filePath);
       if (!destDir.exists()) {
        destDir.mkdirs();
       }
       return destDir;
      }
    }

    2. 定義CrashHandler異常捕獲類:當程序拋出異常後,由CrashHandler先捕獲。將異常堆棧信息和手機系統信息打印到手機制定位置的log文件後,退出。android

public class CrashHandler implements UncaughtExceptionHandler {
    private Context mContext;
    private static CrashHandler mInstance = null;
    // 系統默認的異常處理(默認狀況下,系統會終止當前的異常程序)
    private UncaughtExceptionHandler mDefaultCrashHandler;
 
    private CrashHandler(Context c) {
        // 獲取系統默認的異常處理器
        mDefaultCrashHandler = Thread
                .getDefaultUncaughtExceptionHandler();
        // 將當前實例設爲系統默認的異常處理器
        Thread.setDefaultUncaughtExceptionHandler(this);
        // 獲取Context,方便內部使用
        mContext = c.getApplicationContext();
    }
    public synchronized static CrashHandler create(Context cxt) {
        if (mInstance == null) {
            mInstance = new CrashHandler(cxt);
        }
        return mInstance;
    }
/**
 * 當UncaughtException發生時會回調該函數來處理
 */
 @Override
 public void uncaughtException(Thread thread, Throwable ex) {
      // TODO Auto-generated method stub
      StringBuffer logInfo = new StringBuffer();
      logInfo.append("Exception: ");
      logInfo.append(ex.getMessage());
      logInfo.append("\r\n");
      logInfo.append(getStackMsg(ex));
      logInfo.append("Phone informations:");
      logInfo.append("\r\n");
      try {
           logInfo.append(getPhoneInfo());
            // 導出異常信息到存儲器中
           CrashLog.writeLog(logInfo.toString());
      } catch (Exception e) {
       //忽略異常
      } finally {
       // 若是系統提供了默認的異常處理器,則交給系統去結束程序,
       if (mDefaultCrashHandler != null) {
            mDefaultCrashHandler.uncaughtException(thread, ex);
       } else {
            MyApplication.getInstance().exit();
       }
    }
 }
   
 private static String getStackMsg(Throwable e) {  
      StringBuffer sb = new StringBuffer();  
      StackTraceElement[] stackArray = e.getStackTrace();  
      for (int i = 0; i < stackArray.length; i++) {  
          StackTraceElement element = stackArray[i];  
          sb.append(element.toString() + "\r\n");
      }  
      return sb.toString();
 } 
 private String getPhoneInfo()
            throws NameNotFoundException {
       StringBuffer info = new StringBuffer();
  
        // 應用的版本號
        PackageManager pm = mContext.getPackageManager();
        PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(),
                PackageManager.GET_ACTIVITIES);
        info.append("App Version Name: ");
        info.append(pi.versionName);
        info.append("\r\n");
        // android版本號
        info.append("OS Version: ");
        info.append(Build.VERSION.RELEASE);
        info.append("_");
        info.append(Build.VERSION.SDK_INT);
        info.append("\r\n");
        // 手機制造商
        info.append("Vendor: ");
        info.append(Build.MANUFACTURER);
        info.append("\r\n");
        // 手機型號
        info.append("Model: ");
        info.append(Build.MODEL);
        info.append("\r\n");
        // cpu架構
        info.append("CPU ABI: ");
        info.append(Build.CPU_ABI);
        info.append("\r\n");
        
        return info.toString();
    }
}

3. 自定義Application類,初始化CrashLog和CrashHandler,並提供徹底退出應用的接口exit()。架構

public class MyApplication extends Application{
 // 單例模式
 private static MyApplication mAppInstance;
 // Activity容器
 private List<Activity> mActivityList = new LinkedList<Activity>();
 
 public MyApplication(){ 
 }
 
 public static MyApplication getInstance() {
  if( mAppInstance == null ) {
   mAppInstance = new MyApplication();
  }
  return mAppInstance;
 }
 
 // 每新建一個Activity,都要添加到容器中
 public void addActivity(Activity a){
  mActivityList.add(a);
 }
 
 // 遍歷容器中全部Activity並finish
 public void exit(){
     for (Activity activity : mActivityList) {  
         activity.finish();  
     }  
     System.exit(0);  
  }
 @Override
 public void onCreate() {
     super.onCreate();
     CrashLog.setContext(this);
     CrashHandler.create(this);
 }
}
相關文章
相關標籤/搜索