標籤:
應用發布之後,總有人反饋說發生crash,但是由於拿不到log,我無法定位問題。後來發現,我們應該收集crash日誌,並上傳到伺服器。
國內有很多的三方機構提供了崩潰收集的sdk,我們可以直接拿來使用,比如,我之前做的app使用的是bugHD(http://bughd.com/)提供的服務。
但是崩潰收集的原理是什麼呢?搜尋了一下,發現使用的是java中的uncaughtExceptionHandler,我們可以通過Thread.setDefautUncaughtExceptionHandler()設定我們自己的UncaughtExceptionHandler。它其實是一個介面,實現方法即可。
我寫的一個demo:
import android.os.Looper;import android.widget.Toast;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.PrintWriter;import java.io.StringWriter;import java.io.Writer;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Locale;import java.util.Map;/** * Created by Rowandjj on 2015/5/19. * * 崩潰日誌收集 */public class CrashHandler implements Thread.UncaughtExceptionHandler{ private static CrashHandler sInstance = null; private static Object lock = new Object(); private Thread.UncaughtExceptionHandler mDefaultExceptionHandler; private CrashHandler() { } public static CrashHandler getInstance() { if (sInstance == null) { synchronized (lock) { if (sInstance == null) sInstance = new CrashHandler(); } } return sInstance; } public void register() { mDefaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler(this); } @Override public void uncaughtException(Thread thread, Throwable ex) { //組建記錄檔 final String filename = cacheLog(ex); new Thread(new Runnable() { @Override public void run() { Looper.prepare(); if(filename != null) Toast.makeText(AppEnv.getAppContext(),"程式崩潰了:( \n崩潰日誌已儲存到"+filename+"",Toast.LENGTH_SHORT).show(); Looper.loop(); } }).start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } mDefaultExceptionHandler.uncaughtException(thread,ex); } private String cacheLog(Throwable ex) { if(ex == null) return null; Map<String, String> hardwareInfo = HardwareUtils.getHardwareInfo(); StringBuilder buffer = new StringBuilder(); for (Map.Entry<String, String> me : hardwareInfo.entrySet()) { buffer.append(me.getKey() + ":" + me.getValue() + "\n"); } buffer.append("packname:" + AppEnv.getPackageName() + "\n"); buffer.append("versionname:" + AppEnv.getVersionName() + "\n"); buffer.append("versioncode:" + AppEnv.getVersionCode() + "\n"); Writer writer = new StringWriter(); PrintWriter printWriter = new PrintWriter(writer); ex.printStackTrace(printWriter); Throwable cause = ex.getCause(); while (cause != null) { cause.printStackTrace(printWriter); cause = cause.getCause(); } printWriter.close(); String result = writer.toString(); buffer.append(result); long timestamp = System.currentTimeMillis(); SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.CHINA); String time = formatter.format(new Date()); String filename = "crash-" + time + "-" + timestamp + ".log"; File file = new File(BasicUtils.getStoreDir(), filename); try { if (!file.exists()) file.createNewFile(); FileOutputStream out = new FileOutputStream(file); out.write(buffer.toString().getBytes()); out.close(); Logger.d(this,file.getAbsolutePath()); return file.getAbsolutePath(); } catch (IOException e) { e.printStackTrace(); } return null; }}
然後在你應用的Application中調用
CrashHandler.getInstance().register();
即可。
應用出現crash時,會把log儲存到本地。如果希望上傳到伺服器,加上一個http上傳模組即可。
部分代碼沒有貼出,大家自己腦補。
【安卓筆記】崩潰日誌收集