Chinaunix首页 | 论坛 | 博客
  • 博客访问: 80657
  • 博文数量: 30
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 196
  • 用 户 组: 普通用户
  • 注册时间: 2014-07-13 10:36
个人简介

技术改变世界

文章分类

全部博文(30)

文章存档

2016年(1)

2015年(14)

2014年(15)

我的朋友

分类: Android平台

2015-01-25 21:31:41

转自:http://www.cnblogs.com/stay/archive/2011/07/21/2113167.html
程序员最头疼的事情就是bug和debug。这次debug长达20天,搞的我心力交瘁。累,因为Android兼容性,不同手机会有不同的bug 出来,而且很难复现,所以就上网找了下类似保存错误log到文件再上传到服务器,现把源码也共享出来。上传至服务器的代码我没加。相信大家都有现成的代码 了。

先讲下原理,跟JavaEE的自定义异常捕获一样,将错误一直向上抛,然后在最上层统一处理。这里就可以获得Exception Message,进行保存操作

异常捕获类如下:


点击(此处)折叠或打开

  1. /**
  2.  * @author Stay
  3.  * 在Application中统一捕获异常,保存到文件中下次再打开时上传
  4.  */
  5. public class CrashHandler implements UncaughtExceptionHandler {
  6.     /** 是否开启日志输出,在Debug状态下开启,
  7.      * 在Release状态下关闭以提示程序性能
  8.      * */
  9.     public static final boolean DEBUG = true;
  10.     /** 系统默认的UncaughtException处理类 */
  11.     private Thread.UncaughtExceptionHandler mDefaultHandler;
  12.     /** CrashHandler实例 */
  13.     private static CrashHandler INSTANCE;
  14.     /** 程序的Context对象 */
  15. // private Context mContext;
  16.     /** 保证只有一个CrashHandler实例 */
  17.     private CrashHandler() {}
  18.     /** 获取CrashHandler实例 ,单例模式*/
  19.     public static CrashHandler getInstance() {
  20.         if (INSTANCE == null) {
  21.             INSTANCE = new CrashHandler();
  22.         }
  23.         return INSTANCE;
  24.     }
  25.    
  26.     /**
  27.      * 初始化,注册Context对象,
  28.      * 获取系统默认的UncaughtException处理器,
  29.      * 设置该CrashHandler为程序的默认处理器
  30.      *
  31.      * @param ctx
  32.      */
  33.     public void init(Context ctx) {
  34. // mContext = ctx;
  35.         mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
  36.         Thread.setDefaultUncaughtExceptionHandler(this);
  37.     }
  38.    
  39.     /**
  40.      * 当UncaughtException发生时会转入该函数来处理
  41.      */
  42.     @Override
  43.     public void uncaughtException(Thread thread, Throwable ex) {
  44.         if (!handleException(ex) && mDefaultHandler != null) {
  45.             //如果用户没有处理则让系统默认的异常处理器来处理
  46.             mDefaultHandler.uncaughtException(thread, ex);
  47.         } else { //如果自己处理了异常,则不会弹出错误对话框,则需要手动退出app
  48.             try {
  49.                 Thread.sleep(3000);
  50.             } catch (InterruptedException e) {
  51.             }
  52.             android.os.Process.killProcess(android.os.Process.myPid());
  53.             System.exit(10);
  54.         }
  55.     }
  56.    
  57.     /**
  58.      * 自定义错误处理,收集错误信息
  59.      * 发送错误报告等操作均在此完成.
  60.      * 开发者可以根据自己的情况来自定义异常处理逻辑
  61.      * @return
  62.      * true代表处理该异常,不再向上抛异常,
  63.      * false代表不处理该异常(可以将该log信息存储起来)然后交给上层(这里就到了系统的异常处理)去处理,
  64.      * 简单来说就是true不会弹出那个错误提示框,false就会弹出
  65.      */
  66.     private boolean handleException(final Throwable ex) {
  67.         if (ex == null) {
  68.             return false;
  69.         }
  70. // final String msg = ex.getLocalizedMessage();
  71.         final StackTraceElement[] stack = ex.getStackTrace();
  72.         final String message = ex.getMessage();
  73.         //使用Toast来显示异常信息
  74.         new Thread() {
  75.             @Override
  76.             public void run() {
  77.                 Looper.prepare();
  78. // Toast.makeText(mContext, "程序出错啦:" + message, Toast.LENGTH_LONG).show();
  79. // 可以只创建一个文件,以后全部往里面append然后发送,这样就会有重复的信息,个人不推荐
  80.                 String fileName = "crash-" + System.currentTimeMillis() + ".log";
  81.                 File file = new File(Environment.getExternalStorageDirectory(), fileName);
  82.                 try {
  83.                     FileOutputStream fos = new FileOutputStream(file,true);
  84.                     fos.write(message.getBytes());
  85.                     for (int i = 0; i < stack.length; i++) {
  86.                         fos.write(stack[i].toString().getBytes());
  87.                     }
  88.                     fos.flush();
  89.                     fos.close();
  90.                 } catch (Exception e) {
  91.                 }
  92.                 Looper.loop();
  93.             }
  94.    
  95.         }.start();
  96.         return false;
  97.     }
  98.    
  99.     // TODO 使用HTTP Post 发送错误报告到服务器 这里不再赘述
  100. // private void postReport(File file) {
  101. // 在上传的时候还可以将该app的version,该手机的机型等信息一并发送的服务器,
  102. // Android的兼容性众所周知,所以可能错误不是每个手机都会报错,还是有针对性的去debug比较好
  103. // }
  104. }
  105.  
  106.  

  107. 在Application onCreate时就注册ExceptionHandler,此后只要程序在抛异常后就能捕获到。
  108. public class App extends Application{
  109.         @Override
  110.         public void onCreate() {
  111.             super.onCreate();
  112.             CrashHandler crashHandler = CrashHandler.getInstance();
  113.             //注册crashHandler
  114.             crashHandler.init(getApplicationContext());
  115.         }
  116. }
  117. public class LogActivity extends Activity {
  118.     @Override
  119.     public void onCreate(Bundle savedInstanceState) {
  120.         super.onCreate(savedInstanceState);
  121.         setContentView(R.layout.main);
  122.         try {//制造bug
  123.             File file = new File(Environment.getExternalStorageState() ,"crash.bin");
  124.             FileInputStream fis = new FileInputStream(file);
  125.             byte[] buffer = new byte[1024];
  126.             fis.read(buffer);
  127.         } catch (Exception e) {
  128.             //这里不能再向上抛异常,如果想要将log信息保存起来,则抛出runtime异常,
  129. // 让自定义的handler来捕获,统一将文件保存起来上传
  130.             throw new RuntimeException(e);
  131.         }
  132.     }
  133. }

  134. 注意,如果catch后不throw就默认是自己处理了,ExceptionHandler不会捕获异常了。

  135. 再分享一个Log的封装类,只要在这里设置DEBUG的值就能让控制台是否打印出log
  136. public class DebugUtil {
  137.     public static final String TAG = "ICON";
  138.     public static final boolean DEBUG = true;
  139.      
  140.     public static void toast(Context context,String content){
  141.         Toast.makeText(context, content, Toast.LENGTH_SHORT).show();
  142.     }
  143.      
  144.     public static void debug(String tag,String msg){
  145.         if (DEBUG) {
  146.             Log.d(tag, msg);
  147.         }
  148.     }
  149.      
  150.     public static void debug(String msg){
  151.         if (DEBUG) {
  152.             Log.d(TAG, msg);
  153.         }
  154.     }
  155.      
  156.     public static void error(String tag,String error){
  157.         Log.e(tag, error);
  158.     }
  159.      
  160.     public static void error(String error){
  161.         Log.e(TAG, error);
  162.     }
  163. }

阅读(818) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~