转自:http://www.cnblogs.com/draem0507/archive/2013/05/25/3099461.html
一、为什么要Crash
crash可以理解成堕落,垮台。按照我们通俗理解就是android App 因为不可预知的因素导致奔溃。
即使我们的程序发布前,经历了很多的测试,但是经过无数用户各种使用情况之后,可能会发生意想不到的crash.
为了及时反馈bug,通常我们都需要一个crash机制,以让开发人员尽快了解到问题所在,在下个版本中及时改进。
二、如何做到Crash
java的Thread中有一个UncaughtExceptionHandler接口,该接口的作用主要是为了 当 Thread 因未捕获的异常而突然终止时,调用处理程序。
接口下面有setDefaultUncaughtExceptionHandler(
Thread.UncaughtExceptionHandler eh)
方法,方法主要作用为设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序。
通用demo如下
public class DefaultExceptionHandler implements UncaughtExceptionHandler { private Context act = null; public DefaultExceptionHandler(Context act) { this.act = act; } @Override public void uncaughtException(Thread thread, Throwable ex) { // 收集异常信息 并且发送到服务器 sendCrashReport(ex); // 等待半秒 try { Thread.sleep(500); } catch (InterruptedException e) { // } // 处理异常 handleException(); } private void sendCrashReport(Throwable ex) { StringBuffer exceptionStr = new StringBuffer(); exceptionStr.append(ex.getMessage()); StackTraceElement[] elements = ex.getStackTrace(); for (int i = 0; i < elements.length; i++) { exceptionStr.append(elements[i].toString()); } //TODO //发送收集到的Crash信息到服务器 } private void handleException() { //TODO //这里可以对异常进行处理。 //比如提示用户程序崩溃了。 //比如记录重要的信息,尝试恢复现场。 //或者干脆记录重要的信息后,直接杀死程序。 } }
在主线程中调用
Thread.setDefaultUncaughtExceptionHandler(new DefaultExceptionHandler(this.getApplicationContext()));
之前一直对公司项目的CrashHandler类不是很熟悉,这里结合项目代码,看下是如何具体实现的
首先,在AndroidManifest.xml中的application节点中配置name
<application android:name="com.newland.mbop.application.CrashHandlerApp">
CrashHandlerApp中初始化CrashHandler(实现UncaughtExceptionHandler的实现类)
@Override public void onCreate() { CrashHandler ch = CrashHandler.getInstance(); ch.init(this); super.onCreate(); }
最后看下CrashHandler类的具体实现
public class CrashHandler implements UncaughtExceptionHandler { /** 获取CrashHandler实例 */ public static CrashHandler getInstance() { if (INSTANCE == null) INSTANCE = new CrashHandler(); return INSTANCE; } public void init(CrashHandlerApp app) { Log.i("BaseActivity","init()"); this.app = app; // 设置该类为线程默认UncatchException的处理器。 Thread.setDefaultUncaughtExceptionHandler(this); } /** * 当UncaughtException发生时会回调该函数来处理 */ @Override public void uncaughtException(Thread thread, Throwable ex) { System.out.println("system wrong...."); // MBOPApplication app=(MBOPApplication) mainContext; // app.setNeed2Exit(true); //异常信息收集 collectCrashExceptionInfo(thread, ex); //应用程序信息收集 collectCrashApplicationInfo(app); //保存错误报告文件到文件。 saveCrashInfoToFile(ex); //MBOPApplication.setCrash(true); //判断是否为UI线程异常,thread.getId()==1 为UI线程 if (thread.getId() != 1) { // System.out.println("Exception ThreadId" + thread.getId()); thread.interrupt(); //TODO 跳转到IndexActivity System.out.println("Thread ID--->" + Thread.currentThread().getId()); // Intent intent =new Intent(mainContext,IndexActivity.class); // actContext.startActivity(intent); //弹出对话框提示用户是否上传异常日志至服务器 new Thread(){ public void run() {}{ Looper.prepare(); new AlertDialog.Builder(app.getCurrentAct()).setTitle("异常处理").setMessage("您的程序出现异常,是否将异常信息上传至服务器?") .setPositiveButton("是", new OnClickListener() { public void onClick(DialogInterface dialog, int which) { new Thread(new Runnable() { @Override public void run() { sendCrashReportsToServer(app,false); } }).start(); // new Thread(){ // public void run() {}{ // try{ // System.out.println("执行上传线程ID"+this.getId()); // this.sleep(5000); // }catch(Exception e){ // // } // sendCrashReportsToServer(app); // } // }.start(); } }).setNegativeButton("否", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }).create().show(); Looper.loop(); } }.start(); } else { // UserSessionCache usc=UserSessionCache.getInstance(); // ObjectOutputStream oos=null; // try { // oos.writeObject(usc); // } catch (IOException e) { // e.printStackTrace(); // } // SharedPreferences prefenPreferences = mainContext // .getSharedPreferences("IsMBOPCrash",Activity.MODE_PRIVATE); // SharedPreferences.Editor editor = prefenPreferences.edit(); // editor.clear(); // editor.putBoolean("ISCRASH", true); // editor.commit(); // 方案一:将所有Activity放入Activity列表中,然后循环从列表中删除,即可退出程序 for (int i = app.getActivityList().size()-1; i >=0; i--) { Activity act = app.getActivityList().get(i); act.finish(); } CoreCommonMethod.setCrash(app, true); Intent intent = new Intent(app, WelcomeActivity.class); intent.putExtra(WelcomeActivity.EXTRA_DIRECT_TO_INDEX, true); intent.putExtra(WelcomeActivity.EXTRA_USERINFO, UserSessionCache.getInstance().getUserInfo()); intent.putExtra(WelcomeActivity.EXTRA_CURRENT_PORTAL_ID, UserSessionCache.getInstance().getCurrentPortalId()); // intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // app.startActivity(intent); android.os.Process.killProcess(android.os.Process.myPid()); //方案二:直接使用ActivityManager的restartPackage方法关闭应用程序, //此方法在android2.1之后被弃用,不起作用 // ActivityManager am = (ActivityManager) mainContext.getSystemService(Context.ACTIVITY_SERVICE); // am.restartPackage(mainContext.getPackageName()); } } }
一般来说,发生crash的时候,我们需要知道客户端的SDK版本,程序版本,分辨率等等因素