android 系统crash,Android 全局Crash捕捉和处理 短命女 2022-10-05 05:54 255阅读 0赞 有时候app会出现崩溃现象我们无法完全控制,而系统的崩溃界面比较差,可能影响用户体验,而且我们需要对崩溃现象进行处理,因此有了这个需求。 app运行有一个主线程,也就是UI线程,系统奔溃了一般来说是ui线程崩溃了(我们自己设置的一异步线程,一般自己都会做catch),所以,处理的核心就是 Thread.setDefaultUncaughtExceptionHandler(this); 获得主线程中的设置出现未捕捉的异常的Handler,然后自己重新设置这个handler 自己实现的类CrashHandlr集成UncaughtExceptionHandler,主要通过重载uncaughtException方法来处理异常。 在代码中,handleException() 通过一个异步线程显示toast,并进行 收集设备参数信息: collectDeviceInfo(mContext); 保存日志文件:saveCrashInfo2File(ex); 代码如下: /\*\* \* 收集手机全局崩溃时的exception,并log到本地 \* \* @author Jackland\_zgl \* \*/ public class CrashHandler implements UncaughtExceptionHandler \{ public static final String CrashFilePath = "/sdcard/xiaomai/crashlog/"; public static final int LogFileLimit = 10; public static final String TAG = "CrashHandler"; //系统默认的UncaughtException处理类 private Thread.UncaughtExceptionHandler mDefaultHandler; //CrashHandler实例 private static CrashHandler INSTANCE = new CrashHandler(); //程序的Context对象 private Context mContext; //用来存储设备信息和异常信息 private Map infos = new HashMap(); //用于格式化日期,作为日志文件名的一部分 private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); /\*\* 保证只有一个CrashHandler实例 \*/ private CrashHandler() \{ \} /\*\* 获取CrashHandler实例 ,单例模式 \*/ public static CrashHandler getInstance() \{ return INSTANCE; \} /\*\* \* 初始化 \* \* @param context \*/ public void init(Context context) \{ mContext = context; //获取系统默认的UncaughtException处理器 mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); //设置该CrashHandler为程序的默认处理器 Thread.setDefaultUncaughtExceptionHandler(this); \} /\*\* \* 当UncaughtException发生时会转入该函数来处理 \*/ @Override public void uncaughtException(Thread thread, Throwable ex) \{ if (!handleException(ex) && mDefaultHandler != null) \{ //如果用户没有处理则让系统默认的异常处理器来处理 mDefaultHandler.uncaughtException(thread, ex); \} else \{ try \{ Thread.sleep(2000); \} catch (InterruptedException e) \{ Log.e(TAG, "error : ", e); \} //退出程序 android.os.Process.killProcess(android.os.Process.myPid()); System.exit(1); \} \} /\*\* \* 收集设备参数信息 \* @param ctx \*/ public void collectDeviceInfo(Context ctx) \{ try \{ PackageManager pm = ctx.getPackageManager(); PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET\_ACTIVITIES); if (pi != null) \{ String versionName = pi.versionName == null ? "null" : pi.versionName; String versionCode = pi.versionCode + ""; infos.put("versionName", versionName); infos.put("versionCode", versionCode); \} \} catch (NameNotFoundException e) \{ Log.e(TAG, "an error occured when collect package info", e); \} Field\[\] fields = Build.class.getDeclaredFields(); for (Field field : fields) \{ try \{ field.setAccessible(true); infos.put(field.getName(), field.get(null).toString()); \} catch (Exception e) \{ Log.e(TAG, "an error occured when collect crash info", e); \} \} \} /\*\* \* 保存错误信息到文件中 \* \* @param ex \* @return 返回文件名称,便于将文件传送到服务器 \*/ private int saveCrashInfo2File(Throwable ex) \{ //将设备信息变成string StringBuffer sb = new StringBuffer(); for (Map.Entry entry : infos.entrySet()) \{ String key = entry.getKey(); String value = entry.getValue(); sb.append(key + "=" + value + "\\n"); \} //递归获取全部的exception信息 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(); sb.append(result); //将写入的结果 //构造文件名 long timestamp = System.currentTimeMillis(); String time = formatter.format(new Date()); String fileName = "crash-" + time + "-" + timestamp + ".log"; //写文件和限制数量 FileUtils.writeFile2SDCard( CrashFilePath,fileName, sb.toString()); cleanLogFileToN(CrashFilePath); return 1; \} Comparator newfileFinder = new Comparator()\{ @Override public int compare(File x, File y) \{ // TODO Auto-generated method stub if (x.lastModified()>y.lastModified()) return 1; if (x.lastModified() else return 0; \} \}; private int cleanLogFileToN(String dirname)\{ File dir = new File(dirname); if (dir.isDirectory())\{ File\[\] logFiles = dir.listFiles(); if (logFiles.length>LogFileLimit)\{ Arrays.sort(logFiles,newfileFinder ); //从小到大排 //删掉N个以前的 for (int i=0;i logFiles\[i\].delete(); \} \} \} return 1; \} /\*\* \* 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. \* \* @param ex \* @return true:如果处理了该异常信息;否则返回false. \*/ private boolean handleException(Throwable ex) \{ if (ex == null) \{ return false; \} //使用Toast来显示异常信息 new Thread() \{ @Override public void run() \{ Looper.prepare(); Toast.makeText(mContext, "很抱歉,程序出现异常", Toast.LENGTH\_LONG).show(); Looper.loop(); \} \}.start(); //收集设备参数信息 collectDeviceInfo(mContext); //保存日志文件 saveCrashInfo2File(ex); return true; \} \} 文章为原创,转载请注明出处。
还没有评论,来说两句吧...