from:http://blog.csdn.net/way_ping_li/article/details/7927273
你他娘的写一个无bug的程序,但是出了bug,程序崩溃,猿猿你是不想混了吗?
需要一个全局的异常捕获器,当出现一个我们未处理的bug时,捕获它,记录它,然后想干嘛干嘛。
需要先了解两个类:
1、Application:用来管理应用程序的全局状态。在应用程序启动时Application会首先创建,然后才根据情况(Intent)来启动相应的Activity和Service。
2、Thread.UncaughtExceptionHandler:线程未捕获异常处理器,用来处理异常。如果程序出现了未捕获异常,默认会弹出系统中强制关闭对话框。我们需要实现此接口,并注册为程序中默认未捕获异常处理。这样当未捕获异常发生时,就可做一些个性化的异常处理操作。
抽吸剥茧分析分析:
第一层:先来实现基本的捕获未处理异常
public class CrashHandler implements UncaughtExceptionHandler { <span style="white-space:pre"> </span>//当UncaughtException发生时会转入该重写的方法来处理 @Override public void uncaughtException(Thread thread, Throwable ex) { } }写了记得用。这只是实现了自己的UncaughtException处理器,想用还得告诉系统:
Thread.setDefaultUncaughtExceptionHandler(this);// 设置该CrashHandler为程序的默认处理器第二层:异常的处理上花点心思。需求描述:自定义的异常处理器未处理,则继续让系统默认的异常处理器来处理;如果处理了,则让程序运行3秒,保证文件保存并上传到服务器。
@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) { e.printStackTrace(); } // 退出程序 android.os.Process.killProcess(android.os.Process.myPid()); System.exit(1); } }获取系统默认的异常处理器:
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();// 获取系统默认的UncaughtException处理器
/** * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. * * @param ex * 异常信息 * @return true 如果处理了该异常信息;否则返回false. */ public boolean handleException(Throwable ex) { if (ex == null) return false; new Thread() { public void run() { Looper.prepare(); Toast.makeText(mContext, "很抱歉,程序出现异常,即将退出", 0).show(); Looper.loop(); } }.start(); // 收集设备参数信息 collectDeviceInfo(mContext); // 保存日志文件 saveCrashInfo2File(ex); return true; }
package com.example.myerrorapplication; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.lang.Thread.UncaughtExceptionHandler; import java.lang.reflect.Field; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Build; import android.os.Environment; import android.os.Looper; import android.util.Log; import android.widget.Toast; public class CrashHandler implements UncaughtExceptionHandler { private static final String TAG = "CrashHandler"; private Thread.UncaughtExceptionHandler mDefaultHandler;// 系统默认的UncaughtException处理类 private static CrashHandler INSTANCE = new CrashHandler();// CrashHandler实例 private Context mContext;// 程序的Context对象 private Map<String, String> info = new HashMap<String, String>();// 用来存储设备信息和异常信息 private SimpleDateFormat format = 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; mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();// 获取系统默认的UncaughtException处理器 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) { e.printStackTrace(); } // 退出程序 android.os.Process.killProcess(android.os.Process.myPid()); System.exit(1); } } /** * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. * * @param ex * 异常信息 * @return true 如果处理了该异常信息;否则返回false. */ public boolean handleException(Throwable ex) { if (ex == null) return false; new Thread() { public void run() { Looper.prepare(); Toast.makeText(mContext, "很抱歉,程序出现异常,即将退出", 0).show(); Looper.loop(); } }.start(); // 收集设备参数信息 collectDeviceInfo(mContext); // 保存日志文件 saveCrashInfo2File(ex); return true; } /** * 收集设备参数信息 * * @param context */ public void collectDeviceInfo(Context context) { try { PackageManager pm = context.getPackageManager();// 获得包管理器 PackageInfo pi = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES);// 得到该应用的信息,即主Activity if (pi != null) { String versionName = pi.versionName == null ? "null" : pi.versionName; String versionCode = pi.versionCode + ""; info.put("versionName", versionName); info.put("versionCode", versionCode); } } catch (NameNotFoundException e) { e.printStackTrace(); } Field[] fields = Build.class.getDeclaredFields();// 反射机制 for (Field field : fields) { try { field.setAccessible(true); info.put(field.getName(), field.get("").toString()); Log.d(TAG, field.getName() + ":" + field.get("")); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } } private String saveCrashInfo2File(Throwable ex) { StringBuffer sb = new StringBuffer(); for (Map.Entry<String, String> entry : info.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); sb.append(key + "=" + value + "\r\n"); } Writer writer = new StringWriter(); PrintWriter pw = new PrintWriter(writer); ex.printStackTrace(pw); Throwable cause = ex.getCause(); // 循环着把所有的异常信息写入writer中 while (cause != null) { cause.printStackTrace(pw); cause = cause.getCause(); } pw.close();// 记得关闭 String result = writer.toString(); sb.append(result); // 保存文件 long timetamp = System.currentTimeMillis(); String time = format.format(new Date()); String fileName = "crash-" + time + "-" + timetamp + ".log"; if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { try { File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "crash"); Log.i("CrashHandler", dir.toString()); if (!dir.exists()) dir.mkdir(); FileOutputStream fos = new FileOutputStream(new File(dir, fileName)); fos.write(sb.toString().getBytes()); fos.close(); return fileName; } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } return null; } }
public class CrashApplication extends Application { @Override public void onCreate() { super.onCreate(); CrashHandler crashHandler=CrashHandler.getInstance(); crashHandler.init(this); } }
<application android:name=".CrashApplication" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > ... </application>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>