Android 如何收集發行程式的崩潰資訊

來源:互聯網
上載者:User

下面我就說說如何收集程式運行過程的異常資訊。需要的朋友可以過來參考下 

我們寫程式的時候都希望能寫出一個沒有任何Bug的程式,期望在任何情況下都不會發生程式崩潰。不過理想是豐滿的,現實是骨感的。沒有一個程式員能 保證自己寫的程式絕對不會出現異常崩潰。特別是針對使用者數達到幾十萬幾百萬的程式,當你使用者數達到一定數量級後,就算你的程式出現個別異常崩潰情況也不用 驚訝。

既然我們寫的程式都有可能發生異常崩潰,如果是還沒發布的程式,我們可以通過測試抓取Log來分析。不過針對已經發布的程式,我們沒法重現現象,所以讓使用者反饋程式異常資訊就很重要。下面我們說說如何收集程式運行過程的異常資訊。

1、Android異常捕獲介面

複製代碼 代碼如下:
//當線程因未捕獲的異常而突然終止時,調用處理常式的介面
static interface UncaughtExceptionHandler


2、設定線程捕獲異常
從上面的介面我們可以看到,這個介面是針對線程來說,也就是說我們如果需要監控某個線程運行情況,只要把這個介面實現了,然後把監控方法設定到具體的線程裡面即可。一般來說,我們最需要監控的就是我們的UI線程也就是主線程。

複製代碼 代碼如下:
//設定當線程由於未捕獲到異常而突然終止,並且沒有為該線程定義其他處理常式時所調用的預設處理常式。
static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)


3、UncaughtExceptionHandler 執行個體

複製代碼 代碼如下:
class MythouCrashHandler implements UncaughtExceptionHandler
{
    private static final String TAG = "MythouCrashHandler---->";
    private UncaughtExceptionHandler defaultUEH;
//建構函式,擷取預設的處理方法
    public MythouCrashHandler()
    {
        this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
    }
//這個介面必須重寫,用來處理我們的異常資訊
    @Override
    public void uncaughtException(Thread thread, Throwable ex)
    {
        final Writer result = new StringWriter();
        final PrintWriter printWriter = new PrintWriter(result);
//擷取跟蹤的棧資訊,除了系統棧資訊,還把手機型號、系統版本、編譯版本的唯一標示
        StackTraceElement[] trace = ex.getStackTrace();
        StackTraceElement[] trace2 = new StackTraceElement[trace.length+3];
        System.arraycopy(trace, 0, trace2, 0, trace.length);
        trace2[trace.length+0] = new StackTraceElement("Android", "MODEL", android.os.Build.MODEL, -1);
        trace2[trace.length+1] = new StackTraceElement("Android", "VERSION", android.os.Build.VERSION.RELEASE, -1);
        trace2[trace.length+2] = new StackTraceElement("Android", "FINGERPRINT", android.os.Build.FINGERPRINT, -1);
//追加資訊,因為後面會回調預設的處理方法
        ex.setStackTrace(trace2);
        ex.printStackTrace(printWriter);
//把上面擷取的堆棧資訊轉為字串,列印出來
        String stacktrace = result.toString();
        printWriter.close();
        Log.e(TAG, stacktrace);
        //這裡把剛才異常堆棧資訊寫入SD卡的Log日誌裡面
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
        {
            String sdcardPath = Environment.getExternalStorageDirectory().getPath();
            writeLog(stacktrace, sdcardPath + "/mythou");
        }
        defaultUEH.uncaughtException(thread, ex);
    }
//寫入Log資訊的方法,寫入到SD卡裡面
    private void writeLog(String log, String name)
    {
        CharSequence timestamp = DateFormat.format("yyyyMMdd_kkmmss", System.currentTimeMillis());
        String filename = name + "_" + timestamp + ".log";
        try
        {
            FileOutputStream stream = new FileOutputStream(filename);
            OutputStreamWriter output = new OutputStreamWriter(stream);
            BufferedWriter bw = new BufferedWriter(output);
//寫入相關Log到檔案
            bw.write(log);
            bw.newLine();
            bw.close();
            output.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
}


上 面就是實現了擷取處理跟蹤資訊的方法,上面的方法是參照VLC的異常處理機制編寫的。做了一些簡單修改。不過上面只是擷取了異常資訊,如果程式安裝到使用者 機器上,我們沒法擷取到這些資訊,總不能讓使用者把機器拿過來給你,然後你把Log拷貝出來吧。(這個我以前做嵌入式的時候到試過,讓客戶把機器拿過來,拷 貝裡面的Log,那時候做的機器無法連網。現在想起來都糾結,O(∩_∩)O哈哈~) 為了不再糾結,我們需要一個可以把Log發送到我們伺服器的功能,下面是把一個服務資訊發送到我們指定伺服器功能。

3、通過網路發送Log

複製代碼 代碼如下:
public class SendCrashLog extends AsyncTask<String, String, Boolean>
    {
        public SendCrashLog() { }
        @Override
        protected Boolean doInBackground(String... params)
        {
            if (params[0].length() == 0)
                return false;
            HttpClient httpClient = new DefaultHttpClient();
//你的伺服器,這裡只是舉個例子。把異常資訊當作http請求發送到伺服器
            HttpPost httpPost = new HttpPost("http://www.mythou/getlog.php");
//這裡把相關的異常資訊轉為http post請求的資料參數
            try {
                List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
                nameValuePairs.add(new BasicNameValuePair("model", params[0]));
                nameValuePairs.add(new BasicNameValuePair("device", params[1]));
                httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
//發送相關請求資訊
                httpClient.execute(httpPost);
            } catch (ClientProtocolException e) {
                e.printStackTrace();
                return false;
            } catch (IOException e) {
                e.printStackTrace();
                return false;
            }
            Log.d(TAG, "Device model sent.");
            return true;
        }
        @Override
        protected void onPostExecute(Boolean result) {
        }
    }


上 面就是我上一篇文章講的非同步任務的使用,我們在非同步任務裡面編寫了一個發送http請求的服務,用來把相關的異常資訊發送到我們指定的伺服器上面。這個需 要你的伺服器解析發送的http請求,這個難度不大,一般做個web的人都知道如何做。在上面的異常處理裡面再調用這裡的發送方法:

複製代碼 代碼如下:
SendCrashLogsendLog = new SendCrashLog();
//剛才的異常資訊字串
sendLog .execute(stacktrace);


通過上面的方法就可以把異常資訊發送到指定的伺服器,也就可以跟蹤客戶使用軟體的情況,方便我們修改程式的問題。當然這個資訊收集一般都隱私和後台流量問題,這個需要在程式裡面做點提示,免得背上流氓軟體的罵名。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.