將安卓app閃退信息保存在本地或服務(wù)器的工具類CrashHandler

在我剛剛實(shí)習(xí)的時(shí)候,有一個(gè)測試曾經(jīng)問我,能不能把安卓app閃退時(shí)候的錯(cuò)誤信息保存在本地文件夾或者上傳到服務(wù)器。他說這樣做可以把客戶反映的閃退問題、而且我們公司不能及時(shí)重現(xiàn)BUG的時(shí)候去使用。當(dāng)時(shí),我的回答是否定的,因?yàn)槲耶?dāng)時(shí)并不知道原來安卓早就有UncaughtExceptionHandler可以去全局捕獲異常,直到我看了Android開發(fā)藝術(shù)探索這本書。其實(shí)寫這篇文章不是為了去展示什么,因?yàn)闀?、網(wǎng)上都有一模一樣的繼承UncaughtExceptionHandler寫一個(gè)工具類。寫這篇文章我只是想糾正當(dāng)年的錯(cuò)誤并且可以作為自己項(xiàng)目的工具類去使用,畢竟身為程序猿都不喜歡跟“萬惡”的客戶和“死神”般的測試有過多的沖突摩擦。當(dāng)他們發(fā)現(xiàn)app有閃退問題的時(shí)候,你只需要叫他們把a(bǔ)pp“臨終”前保存在本地的文件打開,這里有幾個(gè)好處:

1.可以輕松的擺脫“萬惡”的客戶和“死神”般的測試的糾纏,有時(shí)候客戶和測試不在身邊,遠(yuǎn)距離就可以找到問題所在;
2.你就可以省去很多功夫去重現(xiàn)BUG,可以留下多點(diǎn)時(shí)間跟測試的妹子聊天去;
3.可以把國內(nèi)各大手機(jī)商改過的安卓系統(tǒng)無緣無故會(huì)在某些型號(hào)的手機(jī)上出現(xiàn)閃退情況,捕獲記錄下來,做好適配工作。

如果有很多app的內(nèi)容要跟測試妹子深入了解的話,你可以把這篇文章省略掉~
好吧,言歸正傳,UncaughtExceptionHandler是全局捕獲異常的,為app意外中止的提供一些處理的方法。用的時(shí)候我們只需要實(shí)現(xiàn)UncaughtExceptionHandler這個(gè)接口,重寫一些方法,就可以做到把異常信息保存在本地或者上傳到服務(wù)器。
代碼如下:

public class CrashHandler implements Thread.UncaughtExceptionHandler {    
   private static final String TAG = "CrashHandler";    
   private static final boolean DEBUG = true;   
   private static final String PATH = Environment.getExternalStorageDirectory().getPath() + "/CrashTest/log/"; 
   private static final String FILE_NAME = "crash";  
   private static final String FILE_NAME_SUFFIX = ".txt";  
   private static CrashHandler sInstance = new CrashHandler();    
   private Thread.UncaughtExceptionHandler mDefaultCrashHandler; 
   private Context mContext;  
   private CrashHandler(){ 
   }  
   public static CrashHandler getsInstance(){   
       return sInstance; 
   } 
   public void init(Context context){  
      mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler();    
      Thread.setDefaultUncaughtExceptionHandler(this);   
      mContext = context.getApplicationContext(); 
   }  
  /**  
   * 這個(gè)是最關(guān)鍵的函數(shù),當(dāng)程序中有未被捕獲的異常,系統(tǒng)將會(huì)自動(dòng)調(diào)用uncaughtException方法  
   * thread為出現(xiàn)未捕獲異常的線程,ex為未捕獲的異常,有了這個(gè)ex,我們就可以得到異常信息   
   * @param thread  
   * @param ex  
   */  
   @Override 
   public void uncaughtException(Thread thread, Throwable ex) { 
       try {     
               //導(dǎo)出異常信息到SD卡中  
              dumpExceptionToSDCard(ex);  
             //這里可以上傳異常信息到服務(wù)器,便于開發(fā)人員分析日志從而解決bug    
             uploadExceptionToServer(); 
           }catch (IOException e){ 
               e.printStackTrace(); 
           }   
          ex.printStackTrace();  
        //如果系統(tǒng)提供默認(rèn)的異常處理器,則交給系統(tǒng)去結(jié)束程序,否則就由自己結(jié)束自己
        if(mDefaultCrashHandler != null){  
          mDefaultCrashHandler.uncaughtException(thread, ex);      
        }else { 
           //自己處理  
           try {
               //延遲2秒殺進(jìn)程   
               Thread.sleep(2000);              
               Toast.makeText(mContext, "程序出錯(cuò)了~", Toast.LENGTH_SHORT).show();   
              } catch (InterruptedException e) {   
             Log.e(TAG, "error : ", e);   
         }    
        android.os.Process.killProcess(Process.myPid()); 
       }  
  }  
  private void dumpExceptionToSDCard(Throwable ex) throws IOException{  
      //如果SD卡不存在或無法使用,則無法把異常信息寫入SD卡        
      if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){  
          if(DEBUG){  
              Log.e(TAG, "sdcard unmounted,skip dump exception");                
              return;  
          }  
      }  
      File dir = new File(PATH);  
      if(!dir.exists()){   
         dir.mkdirs();  
      }  
      long current = System.currentTimeMillis();  
      String time = new SimpleDateFormat("yyyy-MM-dd HH:MM:SS").format(new Date(current));  
      File file = new File(PATH + FILE_NAME + time + FILE_NAME_SUFFIX);  
      try {   
          PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file)));  
          pw.println(time);  
          dumpPhoneInfo(pw);  
          pw.println();  
          ex.printStackTrace(pw);  
          pw.close();  
          Log.e(TAG, "dump crash info seccess");  
      }catch (Exception e){  
          Log.e(TAG,e.getMessage());  
          Log.e(TAG,"dump crash info failed");  
      }  
  }  
  private void dumpPhoneInfo(PrintWriter pw)throws PackageManager.NameNotFoundException{  
      PackageManager pm = mContext.getPackageManager();  
      PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(),                PackageManager.GET_ACTIVITIES);  
      pw.print("App Version: ");  
      pw.print(pi.versionName);  
      pw.print('_');  
      pw.println(pi.versionCode);  
      //Android版本號(hào)  
      pw.print("OS Version: ");  
      pw.print(Build.VERSION.RELEASE);  
      pw.print("_");  
      pw.print(Build.VERSION.SDK_INT);  
      //手機(jī)制造商  
      pw.print("Vendor: ");  
      pw.print(Build.MANUFACTURER);  
      //手機(jī)型號(hào)  
      pw.print("Model: ");  
      pw.println(Build.MODEL);  
      //CPU架構(gòu)  
      pw.print("CPU ABI: ");  
      pw.println(Build.CPU_ABI);  
  }  
  private void uploadExceptionToServer(){  
      //將異常信息發(fā)送到服務(wù)器  
  }
}

就是這么簡單一個(gè)工具類,是不是很簡單?好吧下面我們來看看怎么使用~

CrashHandler的使用.png

只需要在application獲取CrashHandler的單例和初始化就可以做到全局捕獲異常了,跟一些第三方的框架初始化沒什么區(qū)別吧~
最后看一下效果圖:

自己拋出一個(gè)異常做測試.png

點(diǎn)擊這個(gè)按鈕,我們就看到app閃退了,然后我們?nèi)ピ摫4婺夸浵驴纯从惺裁磣

測試結(jié)果.png

我們可以看到我們還可以把安卓版本、手機(jī)型號(hào)、運(yùn)營商輸出來,考慮到國內(nèi)各大手機(jī)商改過的安卓系統(tǒng)無緣無故會(huì)在某些型號(hào)的手機(jī)上出現(xiàn)閃退情況,捕獲到這些異常還是很有必要的。
好吧,其實(shí)以上的代碼很大部分都是來源于Android開發(fā)藝術(shù)探索這本書的,有興趣的同學(xué)也可以去看一下,我只是想告訴更多還不知道的同學(xué),UncaughtExceptionHandler可以把你的閃退信息保存到本地或者上傳到服務(wù)器上!
源碼下載鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,936評論 25 709
  • 文章最早發(fā)布于我的微信公眾號(hào) Android_De_Home 中,歡迎大家掃描下面二維碼關(guān)注微信公眾獲取更多知識(shí)...
    sydMobile閱讀 4,176評論 0 3
  • 艾瑞巴蒂,又到周五了,靜靜繼續(xù)給大家播報(bào)新聞,萬達(dá)酒店要沖出中國了,而今旅(Hotel Jen)也要布局亞洲,哎喲...
    Miss_Raquel閱讀 308評論 0 0
  • 做一件事最好的時(shí)間是在10年前,其次就是現(xiàn)在,我還總想著等我找到一個(gè)女朋友以后就開始學(xué)習(xí),這tmd真的是太天真了,...
    現(xiàn)在的孩子真是閱讀 157評論 0 0
  • - 地址與值的關(guān)系 舉例:圖中表明了計(jì)算機(jī)中內(nèi)存的存在形式,矩形框上面的整數(shù)為地址編號(hào)(內(nèi)存完成編號(hào))。這樣的編號(hào)...
    安公子_閱讀 215評論 0 0

友情鏈接更多精彩內(nèi)容