应用发布之后,总有人反馈说发生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上传模块即可。
部分代码没有贴出,大家自己脑补。
时间: 2024-11-09 22:13:03