学习自
https://www.jianshu.com/p/91f494c7adf6
更推荐去集成sdk,本文侧重原理的解读
腾讯https://bugly.qq.com/v2/index
友盟http://www.umeng.com/
收集工具类
public class ExceptionCrashHandler implements Thread.UncaughtExceptionHandler { /*** * 单例 */ public static ExceptionCrashHandler getInstance() { return SingletonHolder.INSTANCE; } static class SingletonHolder { static ExceptionCrashHandler INSTANCE = new ExceptionCrashHandler(); } private ExceptionCrashHandler() {} /*** * 初始化操作 */ private Application mContext; public void init(Application app) { this.mContext = app; Thread.currentThread().setUncaughtExceptionHandler(this); } /*** * 拦截到crash */ private static final String TAG = "xbh"; @Override public void uncaughtException(Thread t, Throwable ex) { //获取信息(崩溃、手机、版本)并写入文件 String crashFileName = saveInfoToSD(ex); //你去手机或者模拟器的这个目录下看就可以了 //Log.e(TAG, "fileName --> " + crashFileName); //我下次登录需要上传崩溃信息到服务器里,所以我需要缓存crash文件的名称 cacheCrashFile(crashFileName); } /// 下面的是util/// // /** * 缓存崩溃日志文件 * * @param fileName */ private void cacheCrashFile(String fileName) { SharedPreferences sp = mContext.getSharedPreferences("crash", Context.MODE_PRIVATE); sp.edit().putString("CRASH_FILE_NAME", fileName).apply(); } /** * 获取崩溃文件名称 * * @return */ public File getCrashFile() { String crashFileName = mContext.getSharedPreferences("crash", Context.MODE_PRIVATE).getString("CRASH_FILE_NAME", ""); return new File(crashFileName); } /** * 保存获取的 软件信息,设备信息和出错信息保存在SDcard中 * * @param ex * @return */ private String saveInfoToSD(Throwable ex) { String fileName = null; StringBuffer sb = new StringBuffer(); for (Map.Entry<String, String> entry : obtainSimpleInfo(mContext) .entrySet()) { String key = entry.getKey(); String value = entry.getValue(); sb.append(key).append(" = ").append(value).append("\n"); } sb.append(obtainExceptionInfo(ex)); if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { File dir = new File(mContext.getFilesDir() + File.separator + "crash" + File.separator); // 先删除之前的异常信息 if (dir.exists()) { deleteDir(dir); } // 再从新创建文件夹 if (!dir.exists()) { dir.mkdir(); } try { fileName = dir.toString() + File.separator + getAssignTime("yyyy_MM_dd_HH_mm") + ".txt"; FileOutputStream fos = new FileOutputStream(fileName); fos.write(sb.toString().getBytes()); fos.flush(); fos.close(); } catch (Exception e) { e.printStackTrace(); } } return fileName; } /** * 返回当前日期根据格式 **/ private String getAssignTime(String dateFormatStr) { DateFormat dataFormat = new SimpleDateFormat(dateFormatStr); long currentTime = System.currentTimeMillis(); return dataFormat.format(currentTime); } /** * 获取一些简单的信息,软件版本,手机版本,型号等信息存放在HashMap中 * * @return */ private HashMap<String, String> obtainSimpleInfo(Context context) { HashMap<String, String> map = new HashMap<>(); PackageManager mPackageManager = context.getPackageManager(); PackageInfo mPackageInfo = null; try { mPackageInfo = mPackageManager.getPackageInfo( context.getPackageName(), PackageManager.GET_ACTIVITIES); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } map.put("versionName", mPackageInfo.versionName); map.put("versionCode", "" + mPackageInfo.versionCode); map.put("MODEL", "" + Build.MODEL); map.put("SDK_INT", "" + Build.VERSION.SDK_INT); map.put("PRODUCT", "" + Build.PRODUCT); map.put("MOBLE_INFO", getMobileInfo()); return map; } /** * Cell phone information * * @return */ private static String getMobileInfo() { StringBuilder sb = new StringBuilder(); try { Field[] fields = Build.class.getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); String name = field.getName(); String value = field.get(null).toString(); sb.append(name + "=" + value); sb.append("\n"); } } catch (Exception e) { e.printStackTrace(); } return sb.toString(); } /** * 获取系统未捕捉的错误信息 * * @param throwable * @return */ private String obtainExceptionInfo(Throwable throwable) { StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); throwable.printStackTrace(printWriter); printWriter.close(); return stringWriter.toString(); } /** * 递归删除目录下的所有文件及子目录下所有文件 * * @param dir 将要删除的文件目录 * @return boolean Returns "true" if all deletions were successful. If a * deletion fails, the method stops attempting to delete and returns * "false". */ private boolean deleteDir(File dir) { if (dir.isDirectory()) { String[] children = dir.list(); // 递归删除目录中的子目录下 for (int i = 0; i < children.length; i++) { boolean success = deleteDir(new File(dir, children[i])); if (!success) { return false; } } } // 目录此时为空,可以删除 return true; } }
Application中
public class App extends Application { @Override public void onCreate() { super.onCreate(); ExceptionCrashHandler.getInstance().init(this); } }
这样在下一次登录的时候 就可以进行一个崩溃信息的上传了
拿到这个file,然后上传这个file
File crashFile = ExceptionCrashHandler.getInstance().getCrashFile();
上传这里就不上传了 我们弄个crash的例子然后看看本地保存的crash信息
很nice,不过还是推荐sdk