Android 如何收集已發(fā)布程序的崩潰信息
我們寫程序的時候都希望能寫出一個沒有任何Bug的程序,期望在任何情況下都不會發(fā)生程序崩潰。不過理想是豐滿的,現(xiàn)實是骨感的。沒有一個程序員能保證自己寫的程序絕對不會出現(xiàn)異常崩潰。特別是針對用戶數(shù)達到幾十萬幾百萬的程序,當你用戶數(shù)達到一定數(shù)量級后,就算你的程序出現(xiàn)個別異常崩潰情況也不用驚訝。
既然我們寫的程序都有可能發(fā)生異常崩潰,如果是還沒發(fā)布的程序,我們可以通過測試抓取Log來分析。不過針對已經(jīng)發(fā)布的程序,我們沒法重現(xiàn)現(xiàn)象,所以讓用戶反饋程序異常信息就很重要。下面我們說說如何收集程序運行過程的異常信息。
1、Android異常捕獲接口
//當線程因未捕獲的異常而突然終止時,調(diào)用處理程序的接口
static interface UncaughtExceptionHandler
2、設(shè)置線程捕獲異常
從上面的接口我們可以看到,這個接口是針對線程來說,也就是說我們?nèi)绻枰O(jiān)控某個線程運行情況,只要把這個接口實現(xiàn)了,然后把監(jiān)控方法設(shè)置到具體的線程里面即可。一般來說,我們最需要監(jiān)控的就是我們的UI線程也就是主線程。
//設(shè)置當線程由于未捕獲到異常而突然終止,并且沒有為該線程定義其他處理程序時所調(diào)用的默認處理程序。
static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
3、UncaughtExceptionHandler 實例
class MythouCrashHandler implements UncaughtExceptionHandler
{
private static final String TAG = "MythouCrashHandler---->";
private UncaughtExceptionHandler defaultUEH;
//構(gòu)造函數(shù),獲取默認的處理方法
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);
//獲取跟蹤的棧信息,除了系統(tǒng)棧信息,還把手機型號、系統(tǒng)版本、編譯版本的唯一標示
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);
//追加信息,因為后面會回調(diào)默認的處理方法
ex.setStackTrace(trace2);
ex.printStackTrace(printWriter);
//把上面獲取的堆棧信息轉(zhuǎn)為字符串,打印出來
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);
//寫入相關(guān)Log到文件
bw.write(log);
bw.newLine();
bw.close();
output.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
上面就是實現(xiàn)了獲取處理跟蹤信息的方法,上面的方法是參照VLC的異常處理機制編寫的。做了一些簡單修改。不過上面只是獲取了異常信息,如果程序安裝到用戶機器上,我們沒法獲取到這些信息,總不能讓用戶把機器拿過來給你,然后你把Log拷貝出來吧。(這個我以前做嵌入式的時候到試過,讓客戶把機器拿過來,拷貝里面的Log,那時候做的機器無法聯(lián)網(wǎng)?,F(xiàn)在想起來都糾結(jié),O(∩_∩)O哈哈~) 為了不再糾結(jié),我們需要一個可以把Log發(fā)送到我們服務(wù)器的功能,下面是把一個服務(wù)信息發(fā)送到我們指定服務(wù)器功能。
3、通過網(wǎng)絡(luò)發(fā)送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();
//你的服務(wù)器,這里只是舉個例子。把異常信息當作http請求發(fā)送到服務(wù)器
HttpPost httpPost = new HttpPost("http://www.mythou/getlog.php");
//這里把相關(guān)的異常信息轉(zhuǎn)為http post請求的數(shù)據(jù)參數(shù)
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));
//發(fā)送相關(guān)請求信息
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) {
}
}
上面就是我上一篇文章講的異步任務(wù)的使用,我們在異步任務(wù)里面編寫了一個發(fā)送http請求的服務(wù),用來把相關(guān)的異常信息發(fā)送到我們指定的服務(wù)器上面。這個需要你的服務(wù)器解析發(fā)送的http請求,這個難度不大,一般做個web的人都知道如何做。在上面的異常處理里面再調(diào)用這里的發(fā)送方法:
SendCrashLogsendLog = new SendCrashLog();
//剛才的異常信息字符串
sendLog .execute(stacktrace);
相關(guān)文章
Android檢查手機網(wǎng)絡(luò)狀態(tài)及網(wǎng)絡(luò)類型的方法
這篇文章主要介紹了Android檢查手機網(wǎng)絡(luò)狀態(tài)及網(wǎng)絡(luò)類型的方法,涉及Android檢測手機網(wǎng)絡(luò)狀態(tài)的技巧,需要的朋友可以參考下2015-04-04Android 照片選擇區(qū)域功能實現(xiàn)示例
這篇文章主要介紹了Android 照片選擇區(qū)域功能實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-04-04Android開發(fā)框架之自定義ZXing二維碼掃描界面并解決取景框拉伸問題
這篇文章主要介紹了Android開發(fā)框架之自定義ZXing二維碼掃描界面并解決取景框拉伸問題的相關(guān)資料,非常不錯具有參考借鑒價值,需要的朋友可以參考下2016-06-06Android中imageview.ScaleType使用方法詳細介紹
這篇文章主要介紹了Android中imageview.ScaleType使用方法詳細介紹的相關(guān)資料,需要的朋友可以參考下2017-06-06Android提高之TelephonyManager功能探秘
這篇文章主要介紹了Android的TelephonyManager功能,可以幫助讀者更好的理解Java反射機制,需要的朋友可以參考下2014-08-08