由于需求,公司需要收集程序崩溃,异常退出等信息,然后上网查需资料,写了一个CrashHadler类,只要在程序入口初始化此类就能收集崩溃信息,需要的朋友们可以看一下,崩溃信息收集保存在crash文件夹下,以时间命名
public class CrashHandler implements Thread.UncaughtExceptionHandler { private Thread.UncaughtExceptionHandler mDefaultHandler; private Context mContext; /*储存异常参数的信息*/ private Map<String, String> paramsMap = new HashMap<>(); private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); private String TAG = this.getClass().getSimpleName(); private static CrashHandler mInstance; private CrashHandler() { } public static synchronized CrashHandler getInstance() { if (mInstance == null) { mInstance = new CrashHandler(); } return mInstance; } public void init(Context context) { mContext = context; mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler(this);//设置为系统默认的CrashHandler } /** * uncaughtException 回调函数 */ @Override public void uncaughtException(Thread thread, Throwable ex) { if(!handleException(ex) && mDefaultHandler != null){ mDefaultHandler.uncaughtException(thread,ex); }else { try { Thread.sleep(3000);//// 如果处理了,让程序继续运行3秒再退出,保证文件保存并上传到服务器 } catch (InterruptedException e) { Log.e(TAG,"error : ",e); } //退出程序,4.4即以上系统使用该方法杀进程的时候app会重启,类似内存不足app挂了系统发广播拉起app的那种情况 android.os.Process.killProcess(android.os.Process.myPid()); System.exit(1);//非正常退出程序 } } /** * 收集错误信息,发送到服务器 * @param ex * @return 处理了异常返回 true, 否则false */ private boolean handleException(Throwable ex){ if(ex == null){ return false; } collectDeviceInfo(mContext); addCustomInfo(); new Thread(){ @Override public void run() { Looper.prepare(); Toast.makeText(mContext, "程序出现异常,即将退出", Toast.LENGTH_SHORT).show(); Looper.loop(); } }.start(); saveCrashInfo2File(ex); return true; } /** * 保存错误信息到文件中 * @param ex * @return 返回文件名称,便于将文件传送到服务器 */ private String saveCrashInfo2File(Throwable ex) { StringBuffer sb = new StringBuffer(); for(Map.Entry<String,String> entry : paramsMap.entrySet()){ String key = entry.getKey(); String value = entry.getValue(); sb.append(key +"="+ value+"\n"); } Writer writer = new StringWriter(); PrintWriter printWriter = new PrintWriter(writer); ex.printStackTrace(printWriter); Throwable cause = ex.getCause(); //循环着把所有的异常信息写入writer中 while (cause != null){ cause.printStackTrace(printWriter); cause = cause.getCause(); } printWriter.close(); String result = writer.toString(); sb.append(result); try{ long timestamp = System.currentTimeMillis(); String time = format.format(new Date()); String fileName = "crash-"+time+"-"+timestamp+".log"; if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ String path = Environment.getExternalStorageDirectory().getAbsolutePath()+"/crash/"; // Log.i("rjx", "saveCrashInfo2File: "+path); File dir = new File(path); if(!dir.exists()){ dir.mkdirs(); } FileOutputStream fos = new FileOutputStream(path+fileName); fos.write(sb.toString().getBytes()); fos.close(); } return fileName; }catch (Exception e){ Log.e(TAG, "an error occured while writing file...", e); } return null; } /** * 添加自定义参数 */ private void addCustomInfo() { } private void collectDeviceInfo(Context mContext) { try { PackageManager pm = mContext.getPackageManager(); PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES); if(pi != null){ String versionName = pi.versionName == null ? "null" : pi.versionName; String versionCode = pi.versionCode + ""; paramsMap.put("versionName",versionName); paramsMap.put("versionCode",versionCode); } } catch (PackageManager.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); paramsMap.put(field.getName(),field.get(null).toString());//都是静态字段,可以传null } catch (IllegalAccessException e) { Log.e(TAG, "an error occured when collect crash info", e); } } } }
因为涉及到写文件,需要在AndroidManifest里面加入
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />如果手机系统6.0异常,需要动态申请:
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { //Android 6.0申请权限 ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1); }else{ Log.i("权限","权限申请ok"); }到此大功告成!
如有错,请纠正,谢谢