1. 程式人生 > >Android將程式崩潰資訊儲存本地檔案

Android將程式崩潰資訊儲存本地檔案

我們先建立一個crash專案,專案結構如圖:


瞭解以下兩個類:android.app.Application和java.lang.Thread.UncaughtExceptionHandler。

Application:用來管理應用程式的全域性狀態。在應用程式啟動時Application會首先建立,然後才會根據情況(Intent)來啟動相應的Activity和Service。本示例中將在自定義加強版的Application中註冊未捕獲異常處理器。

Thread.UncaughtExceptionHandler:執行緒未捕獲異常處理器,用來處理未捕獲異常。如果程式出現了未捕獲異常,預設會彈出系統中強制關閉對話方塊。我們需要實現此介面,並註冊為程式中預設未捕獲異常處理。這樣當未捕獲異常發生時,就可以做一些個性化的異常處理操作。

大家剛才在專案的結構圖中看到的CrashHandler.java實現了Thread.UncaughtExceptionHandler,使我們用來處理未捕獲異常的主要成員,程式碼如下:


  1. package com.way.crash;  
  2. import java.io.File;  
  3. import java.io.FileNotFoundException;  
  4. import java.io.FileOutputStream;  
  5. import java.io.IOException;  
  6. import java.io.PrintWriter;  
  7. import java.io.StringWriter;  
  8. import java.io.Writer;  
  9. import java.lang.Thread.UncaughtExceptionHandler;  
  10. import java.lang.reflect.Field;  
  11. import java.text.SimpleDateFormat;  
  12. import java.util.Date;  
  13. import java.util.HashMap;  
  14. import java.util.Map;  
  15. import android.content.Context;  
  16. import android.content.pm.PackageInfo;  
  17. import android.content.pm.PackageManager;  
  18. import android.content.pm.PackageManager.NameNotFoundException;  
  19. import android.os.Build;  
  20. import android.os.Environment;  
  21. import android.os.Looper;  
  22. import android.util.Log;  
  23. import android.widget.Toast;  
  24. /** 
  25.  * UncaughtException處理類,當程式發生Uncaught異常的時候,由該類來接管程式,並記錄傳送錯誤報告. 
  26.  *  
  27.  * @author way 
  28.  *  
  29.  */
  30. publicclass CrashHandler implements UncaughtExceptionHandler {  
  31.     privatestaticfinal String TAG = "CrashHandler";  
  32.     private Thread.UncaughtExceptionHandler mDefaultHandler;// 系統預設的UncaughtException處理類
  33.     privatestatic CrashHandler INSTANCE = new CrashHandler();// CrashHandler例項
  34.     private Context mContext;// 程式的Context物件
  35.     private Map<String, String> info = new HashMap<String, String>();// 用來儲存裝置資訊和異常資訊
  36.     private SimpleDateFormat format = new SimpleDateFormat(  
  37.             "yyyy-MM-dd-HH-mm-ss");// 用於格式化日期,作為日誌檔名的一部分
  38.     /** 保證只有一個CrashHandler例項 */
  39.     private CrashHandler() {  
  40.     }  
  41.     /** 獲取CrashHandler例項 ,單例模式 */
  42.     publicstatic CrashHandler getInstance() {  
  43.         return INSTANCE;  
  44.     }  
  45.     /** 
  46.      * 初始化 
  47.      *  
  48.      * @param context 
  49.      */
  50.     publicvoid init(Context context) {  
  51.         mContext = context;  
  52.         mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();// 獲取系統預設的UncaughtException處理器
  53.         Thread.setDefaultUncaughtExceptionHandler(this);// 設定該CrashHandler為程式的預設處理器
  54.     }  
  55.     /** 
  56.      * 當UncaughtException發生時會轉入該重寫的方法來處理 
  57.      */
  58.     publicvoid uncaughtException(Thread thread, Throwable ex) {  
  59.         if (!handleException(ex) && mDefaultHandler != null) {  
  60.             // 如果自定義的沒有處理則讓系統預設的異常處理器來處理
  61.             mDefaultHandler.uncaughtException(thread, ex);  
  62.         } else {  
  63.             try {  
  64.                 Thread.sleep(3000);// 如果處理了,讓程式繼續執行3秒再退出,保證檔案儲存並上傳到伺服器
  65.             } catch (InterruptedException e) {  
  66.                 e.printStackTrace();  
  67.             }  
  68.             // 退出程式
  69.             android.os.Process.killProcess(android.os.Process.myPid());  
  70.             System.exit(1);  
  71.         }  
  72.     }  
  73.     /** 
  74.      * 自定義錯誤處理,收集錯誤資訊 傳送錯誤報告等操作均在此完成. 
  75.      *  
  76.      * @param ex 
  77.      *            異常資訊 
  78.      * @return true 如果處理了該異常資訊;否則返回false. 
  79.      */
  80.     publicboolean handleException(Throwable ex) {  
  81.         if (ex == null)  
  82.             returnfalse;  
  83.         new Thread() {  
  84.             publicvoid run() {  
  85.                 Looper.prepare();  
  86.                 Toast.makeText(mContext, "很抱歉,程式出現異常,即將退出"0).show();  
  87.                 Looper.loop();  
  88.             }  
  89.         }.start();  
  90.         // 收集裝置引數資訊
  91.         collectDeviceInfo(mContext);  
  92.         // 儲存日誌檔案
  93.         saveCrashInfo2File(ex);  
  94.         returntrue;  
  95.     }  
  96.     /** 
  97.      * 收集裝置引數資訊 
  98.      *  
  99.      * @param context 
  100.      */
  101.     publicvoid collectDeviceInfo(Context context) {  
  102.         try {  
  103.             PackageManager pm = context.getPackageManager();// 獲得包管理器
  104.             PackageInfo pi = pm.getPackageInfo(context.getPackageName(),  
  105.                     PackageManager.GET_ACTIVITIES);// 得到該應用的資訊,即主Activity
  106.             if (pi != null) {  
  107.                 String versionName = pi.versionName == null ? "null"
  108.                         : pi.versionName;  
  109.                 String versionCode = pi.versionCode + "";  
  110.                 info.put("versionName", versionName);  
  111.                 info.put("versionCode", versionCode);  
  112.             }  
  113.         } catch (NameNotFoundException e) {  
  114.             e.printStackTrace();  
  115.         }  
  116.         Field[] fields = Build.class.getDeclaredFields();// 反射機制
  117.         for (Field field : fields) {  
  118.             try {  
  119.                 field.setAccessible(true);  
  120.                 info.put(field.getName(), field.get("").toString());  
  121.                 Log.d(TAG, field.getName() + ":" + field.get(""));  
  122.             } catch (IllegalArgumentException e) {  
  123.                 e.printStackTrace();  
  124.             } catch (IllegalAccessException e) {  
  125.                 e.printStackTrace();  
  126.             }  
  127.         }  
  128.     }  
  129.     private String saveCrashInfo2File(Throwable ex) {  
  130.         StringBuffer sb = new StringBuffer();  
  131.         for (Map.Entry<String, String> entry : info.entrySet()) {  
  132.             String key = entry.getKey();  
  133.             String value = entry.getValue();  
  134.             sb.append(key + "=" + value + "\r\n");  
  135.         }  
  136.         Writer writer = new StringWriter();  
  137.         PrintWriter pw = new PrintWriter(writer);  
  138.         ex.printStackTrace(pw);  
  139.         Throwable cause = ex.getCause();  
  140.         // 迴圈著把所有的異常資訊寫入writer中
  141.         while (cause != null) {  
  142.             cause.printStackTrace(pw);  
  143.             cause = cause.getCause();  
  144.         }  
  145.         pw.close();// 記得關閉
  146.         String result = writer.toString();  
  147.         sb.append(result);  
  148.         // 儲存檔案
  149.         long timetamp = System.currentTimeMillis();  
  150.         String time = format.format(new Date());  
  151.         String fileName = "crash-" + time + "-" + timetamp + ".log";  
  152.         if (Environment.getExternalStorageState().equals(  
  153.                 Environment.MEDIA_MOUNTED)) {  
  154.             try {  
  155.                 File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +                           File.separator + "crash");  
  156.                 Log.i("CrashHandler", dir.toString());  
  157.                 if (!dir.exists())  
  158.                     dir.mkdir();  
  159.                 FileOutputStream fos = new FileOutputStream(new File(dir,  
  160.                          fileName));  
  161.                 fos.write(sb.toString().getBytes());  
  162.                 fos.close();  
  163.                 return fileName;  
  164.             } catch (FileNotFoundException e) {  
  165.                 e.printStackTrace();  
  166.             } catch (IOException e) {  
  167.                 e.printStackTrace();  
  168.             }  
  169.         }  
  170.         returnnull;  
  171.     }  
  172. }  

 然後,我們需要在應用啟動的時候在Application中註冊一下:

  1. package com.way.crash;  
  2. import android.app.Application;  
  3. publicclass CrashApplication extends Application {  
  4.     @Override
  5.     publicvoid onCreate() {  
  6.         super.onCreate();  
  7.         CrashHandler crashHandler = CrashHandler.getInstance();  
  8.         crashHandler.init(this);  
  9.     }  
  10. }  


最後,為了讓我們的CrashApplication取代android.app.Application的地位,在我們的程式碼中生效,我們需要修改AndroidManifest.xml:

  1. 相關推薦

    Android程式崩潰資訊儲存本地檔案

    我們先建立一個crash專案,專案結構如圖: 瞭解以下兩個類:android.app.Application和java.lang.Thread.UncaughtExceptionHandler。 Application:用來管理應用程式的全域性狀態。在應用程

    Android應用log資訊儲存檔案

    package com.way.util; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutput

    JAVA之IO技術-java程式的異常資訊儲存檔案

    package ioTest.io2; import java.io.FileNotFoundException; import java.io.PrintStream; import java.util.Properties; /* * 將應用程式的異常資訊輸出到指定

    java 遇到未知異常使程式崩潰,輸出jvm的dump崩潰資訊到指定檔案,然後殺死此程序

    1.我們首先需要獲取當前java程序的pid。方法為: //檢視當前程序pid private static void getPID(){ RuntimeMXBean runtime = ManagementFactory.ge

    Android 應用程式崩潰日誌捕捉

    程式崩潰是應用迭代中不可避免的問題,即使有著5年或者10年經驗的程式猿也無法完全保證自己的程式碼沒有任何的bug導致崩潰,現在有一些第三方平臺可以幫助我們蒐集應用程式的崩潰,比如友盟,詳情如下圖 雖然能夠看到崩潰的日誌以及機型等,但還是不是很方便,如果需要精確定位的話需要使用者提供崩潰的時間點、機型

    java 選擇載入或儲存本地檔案

    在用到java進行檔案的選擇和儲存時,我們可以利用java的JFileChooser。 首先是java選擇載入本地檔案 package com.file; import java.io.File; import javax.swing.JFileChooser; import j

    Winows下程式崩潰自動建立Dump檔案以方便跟蹤問題

    首先定義一個預設的異常處理回撥函式: LONG CrashHandler(struct_EXCEPTION_POINTERS* pExceptionInfo) { std::string dumpFileName = "./CrashDump.dump"; H

    Android平臺程式崩潰的型別及原因列舉

    Android平臺程式崩潰大家都應該遇到過,force close和ANR應該是大家遇到較多的。 這裡把Android平臺程式崩潰的各種型別做一個簡述和原因列舉。 1.ANR(可見ANR): 發生場景:應用發生ANR。 崩潰症狀:系統彈出視窗詢問使用者選擇“Force Close”或

    Java編寫爬蟲,並儲存本地檔案,未涉及圖片,視訊的儲存,只是儲存文字內容

    Java Jsoup jar包編寫爬蟲 這個案例內容很簡單,只是設計文字的爬取,未涉及到圖片儲存與視訊儲存。記錄下來只是方便自己的一個記錄、同時希望給向我這樣第一次接觸爬蟲的朋友一個參考!! 個人覺得分為兩步走!當然,我寫了三個檔案,內容如下: 一、開始方法 S

    iOS 錄視訊,相簿選擇視訊,視訊壓縮,儲存本地檔案,播放,上傳

    iOS 錄視訊,相簿選擇視訊,視訊壓縮,儲存本地檔案,播放,上傳 工程中用到了這部分的功能,也糾結了幾天後做完了,現在總結下這部分的東西。 先說描述下需求: (1)從相簿取視訊、錄視訊; (2)視訊轉碼為mp4; (3)儲存在檔案中,覆蓋更新後也能讀取視訊 (4)視訊的

    Android線上收集崩潰資訊

    為什麼要線上收集崩潰資訊? 我們的app上線後後有可能會出現測試階段沒有出現的bug導致崩潰,我們不能及時獲取到崩潰的日誌及時修復,這時就需要在應用崩潰的時候把崩潰的日誌上傳到伺服器以便我們對崩潰的情況進行分析,當然這裡說的是Java 的 UnChecked

    jmeter 傳送http請求,並把獲取到的請求的訂單資訊儲存檔案

    有一個任務,需要頻繁傳送訂單請求,並分析訂單請求中有沒有存在重複訂單號,思路是用jmeter 傳送http請求,使用正則表示式獲取到訂單號,並把訂單號和執行緒號作為引數提供給java請求,在java請求中把訂單號寫到包括有執行緒號的命名檔案中。完成出來的樣子是這樣的 步驟如下: 1、Jme

    Android聯絡人的資訊傳遞到自帶新建聯

    我在做一個專案時,遇到了一個需求,我做的是中國移動的一卡多號專案。就是在一卡多號中的某個副號下面我新建了一個聯絡人這個聯絡人不儲存到系統中。那麼我點選某個聯絡人客戶希望將此聯絡人新增到系統手機通訊錄中並且希望可以編輯此聯絡人的資訊。那麼我就想辦法將此聯絡人的資訊傳遞給系統自帶的新建聯絡人介面中去。我查看了C

    使用dmp檢視程式崩潰資訊

    #include "DbgHelp.h" typedef BOOL (WINAPI* MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,

    CBitmap程式中動態載入 本地檔案上的BMP圖片資源

     HBITMAP   bitmap; BITMAP    bm; bmBkgnd.Detach(); bitmap = (HBITMAP)::LoadImage(NULL,strPath, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION|LR_LOADFROMFILE|LR_D

    Androidjar包打包成dex檔案

    進入sdk/build-tools/27.0.3目錄,將jar包dex.jar拷貝到該目錄下,在空白處按住shift鍵並點選右鍵,選擇“在此處開啟命令列”輸入命令以下命令(注意其中的空格):dx --

    每日一shell之ifconfig補充IP配置資訊寫入配置檔案

    ifconfig可以直接配置網絡卡IP。但是這是屬於一種動態的配置。配置資訊只儲存在當前執行的核心中,系統重啟後,配置將不復存在。 我的環境是centos7 網路配置檔案路徑在 cd /etc/s

    登入等資訊儲存到session中和退出session

    做專案時,可能會將某些資訊儲存在session中,如登入等資訊,這樣方便在某些頁面使用這些儲存的資訊。 要想儲存這些資訊,需要建立一個類,該類裡面定義需要儲存的變數等資訊,當登入後就通過new一個該類

    python讀取 .txt 文字內容以及程式執行結果寫入txt檔案

    ** 1、讀入篇 ** python對處理文字這方面還是很有優勢的,像普通1G左右的文字都可以直接讀到記憶體中去處理,進行文字處理的速度是非常的快。 話不多說,上程式碼,講思路。 #c

    Android收集程式崩潰日誌

    開個頭 程式崩潰是我們開發人員最不想看到的,但也是我們不可避免的。在我們開發階段,當程式發生崩潰的時候,我們需要根據列印的錯誤日誌來定位,分析,解決錯誤。但是當我們把應用釋出到應用市場的之後,使用者使用我們應用的時候因為各種原因程式發生了崩潰,這個是非常影響使