基于Android 错误信息捕获发送至服务器的详解

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

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

异常捕获类如下:

复制代码 代码如下:

/**

 * @author Stay

 *      在Application中统一捕获异常,保存到文件中下次再打开时上传

 */

public class CrashHandler implements UncaughtExceptionHandler {  

    /** 是否开启日志输出,在Debug状态下开启, 

     * 在Release状态下关闭以提示程序性能 

     * */ 

    public static final boolean DEBUG = true;  

    /** 系统默认的UncaughtException处理类 */ 

    private Thread.UncaughtExceptionHandler mDefaultHandler;  

    /** CrashHandler实例 */ 

    private static CrashHandler INSTANCE;  

    /** 程序的Context对象 */ 

//    private Context mContext;  

    /** 保证只有一个CrashHandler实例 */ 

    private CrashHandler() {}  

    /** 获取CrashHandler实例 ,单例模式*/ 

    public static CrashHandler getInstance() {  

        if (INSTANCE == null) {  

            INSTANCE = new CrashHandler();  

        }  

        return INSTANCE;  

    }

/** 

     * 初始化,注册Context对象, 

     * 获取系统默认的UncaughtException处理器, 

     * 设置该CrashHandler为程序的默认处理器 

     *  

     * @param ctx 

     */ 

    public void init(Context ctx) {  

//        mContext = ctx;  

        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();  

        Thread.setDefaultUncaughtExceptionHandler(this);  

    }

/** 

     * 当UncaughtException发生时会转入该函数来处理 

     */ 

    @Override 

    public void uncaughtException(Thread thread, Throwable ex) {  

        if (!handleException(ex) && mDefaultHandler != null) {  

            //如果用户没有处理则让系统默认的异常处理器来处理  

            mDefaultHandler.uncaughtException(thread, ex);  

        } else {  //如果自己处理了异常,则不会弹出错误对话框,则需要手动退出app

            try {  

                Thread.sleep(3000);  

            } catch (InterruptedException e) {  

            }  

            android.os.Process.killProcess(android.os.Process.myPid());  

            System.exit(10);  

        }  

    }

/** 

     * 自定义错误处理,收集错误信息 

     * 发送错误报告等操作均在此完成. 

     * 开发者可以根据自己的情况来自定义异常处理逻辑 

     * @return 

     * true代表处理该异常,不再向上抛异常,

     * false代表不处理该异常(可以将该log信息存储起来)然后交给上层(这里就到了系统的异常处理)去处理,

     * 简单来说就是true不会弹出那个错误提示框,false就会弹出

     */ 

    private boolean handleException(final Throwable ex) {  

        if (ex == null) {  

            return false;  

        }  

//        final String msg = ex.getLocalizedMessage();  

        final StackTraceElement[] stack = ex.getStackTrace();

        final String message = ex.getMessage();

        //使用Toast来显示异常信息  

        new Thread() {  

            @Override 

            public void run() {  

                Looper.prepare();  

//                Toast.makeText(mContext, "程序出错啦:" + message, Toast.LENGTH_LONG).show();  

//                可以只创建一个文件,以后全部往里面append然后发送,这样就会有重复的信息,个人不推荐

                String fileName = "crash-" + System.currentTimeMillis()  + ".log";  

                File file = new File(Environment.getExternalStorageDirectory(), fileName);

                try {

                    FileOutputStream fos = new FileOutputStream(file,true);

                    fos.write(message.getBytes());

                    for (int i = 0; i < stack.length; i++) {

                        fos.write(stack[i].toString().getBytes());

                    }

                    fos.flush();

                    fos.close();

                } catch (Exception e) {

                }

                Looper.loop();  

            }

}.start();  

        return false;  

    }

// TODO 使用HTTP Post 发送错误报告到服务器  这里不再赘述

//    private void postReport(File file) {  

//      在上传的时候还可以将该app的version,该手机的机型等信息一并发送的服务器,

//      Android的兼容性众所周知,所以可能错误不是每个手机都会报错,还是有针对性的去debug比较好

//    }  

}

在Application onCreate时就注册ExceptionHandler,此后只要程序在抛异常后就能捕获到。

复制代码 代码如下:

public class App extends Application{

        @Override 

        public void onCreate() {  

            super.onCreate();  

            CrashHandler crashHandler = CrashHandler.getInstance();  

            //注册crashHandler  

            crashHandler.init(getApplicationContext());  

        }  

}

?public class LogActivity extends Activity {

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        try {//制造bug

            File file = new File(Environment.getExternalStorageState() ,"crash.bin");

            FileInputStream fis = new FileInputStream(file);

            byte[] buffer = new byte[1024];

            fis.read(buffer);

        } catch (Exception e) {

            //这里不能再向上抛异常,如果想要将log信息保存起来,则抛出runtime异常,

//          让自定义的handler来捕获,统一将文件保存起来上传

            throw new RuntimeException(e);

        }

    }

}

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

再分享一个Log的封装类,只要在这里设置DEBUG的值就能让控制台是否打印出log

复制代码 代码如下:

public class DebugUtil {

    public static final String TAG = "ICON";

    public static final boolean DEBUG = true;

public static void toast(Context context,String content){

        Toast.makeText(context, content, Toast.LENGTH_SHORT).show();

    }

public static void debug(String tag,String msg){

        if (DEBUG) {

            Log.d(tag, msg);

        }

    }

public static void debug(String msg){

        if (DEBUG) {

            Log.d(TAG, msg);

        }

    }

public static void error(String tag,String error){

        Log.e(tag, error);

    }

public static void error(String error){

        Log.e(TAG, error);

    }

}

时间: 2024-09-27 09:34:49

基于Android 错误信息捕获发送至服务器的详解的相关文章

基于Android应用中如何反馈Crash报告的详解_Android

为什么需要反馈Crash报告? 做Android应用程序,要尽量避免程序Crash的发生.虽然说零Crash是程序员追逐的最终目标,但是现实的情况是,程序员只能尽量的减少Crash的发生,而几乎不可能完全杜绝Crash.也许,你认为你的应用的健壮性已经近乎完美,轻松的经受住了测试部门魔鬼般的考验,但是当你的应用发布到市场,面对百万甚至千万级别的用户的时候,可能就没有那么幸运了. 基于以上原因,一般的应用程序,都要有一个Crash反馈的机制.程序员可以根据反馈的结果,对当前的版本的代码进行改进,使

基于Android应用中如何反馈Crash报告的详解

为什么需要反馈Crash报告? 做Android应用程序,要尽量避免程序Crash的发生.虽然说零Crash是程序员追逐的最终目标,但是现实的情况是,程序员只能尽量的减少Crash的发生,而几乎不可能完全杜绝Crash.也许,你认为你的应用的健壮性已经近乎完美,轻松的经受住了测试部门魔鬼般的考验,但是当你的应用发布到市场,面对百万甚至千万级别的用户的时候,可能就没有那么幸运了. 基于以上原因,一般的应用程序,都要有一个Crash反馈的机制.程序员可以根据反馈的结果,对当前的版本的代码进行改进,使

Android实现上传文件到服务器实例详解_Android

本实例实现每隔5秒上传一次,通过服务器端获取手机上传过来的文件信息并做相应处理:采用Android+Struts2技术. 一.Android端实现文件上传 1).新建一个Android项目命名为androidUpload,目录结构如下: 2).新建FormFile类,用来封装文件信息 package com.ljq.utils; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundExce

Android开发高仿课程表的布局实例详解_Android

先说下这个demo,这是一个模仿课程表的布局文件,虽然我是个菜鸟,但我还是想留给学习的人一些例子,先看下效果   然后再来看一下我们学校的app 布局分析 先上一张划分好了的布局图 首先整个页面放在一个LinearLayout布局下面,分为上面和下面两个部分,下面一个是显示课程表的详细信息 1:这个没什么好讲的,就是直接一个LinearLayout布局,然后将控件一个TextView用来显示年份,一个View用来当作竖线,一个Spinner用来显示选择周数 2:这个是显示星期几的部件,是我自定义

Android创建与解析XML(三)——详解Sax方式_Android

1. Sax概述 SAX是一种占用内存少且解析速度快的解析器,它采用的是事件启动,不需要解析完整个文档,而是按照内容顺序看文档某个部分是否符合xml语法,如果符合就触发相应的事件,所谓的事件就是些回调方法(callback),这些方法 定义在ContentHandler中,下面是其主要方法: startDocument():当遇到文档的时候就触发这个事件 调用这个方法 可以在其中做些预处理工作,如:申请对象资源 endDocument():当结束文档的时候就触发这个事件 调用这个方法 可以在其中

基于原生ajax与封装的ajax使用方法(详解)

当我们不会写后端接口来测试ajax时,我们可以使用node环境来模拟一个后端接口. 1.模拟后端接口可参考网站整站开发小例子,在打开命令窗口并转到所在项目文件夹下在命令行中输入npm install express --save,安装express中间件. 2.把当中的app.js的内容换成 var express=require('express'); //var path=require('path'); var app=express(); //app.set('view',path.jo

Android ListView监听滑动事件的方法(详解)

ListView的主要有两种滑动事件监听方法,OnTouchListener和OnScrollListener 1.OnTouchListener OnTouchListener方法来自View中的监听事件,可以在监听三个Action事件发生时通过MotionEvent的getX()方法或getY()方法获取到当前触摸的坐标值,来对用户的滑动方向进行判断,并可在不同的Action状态中做出相应的处理 mListView.setOnTouchListener(new View.OnTouchLis

Android实现定时器的五种方法实例详解

一.Timer Timer是Android直接启动定时器的类,TimerTask是一个子线程,方便处理一些比较复杂耗时的功能逻辑,经常与handler结合使用. 跟handler自身实现的定时器相比,Timer可以做一些复杂的处理,例如,需要对有大量对象的list进行排序,在TimerTask中执行不会阻塞子线程,常常与handler结合使用,在处理完复杂耗时的操作后,通过handler来更新UI界面. timer.schedule(task, delay,period); task: Time

Android开发高仿课程表的布局实例详解

先说下这个demo,这是一个模仿课程表的布局文件,虽然我是个菜鸟,但我还是想留给学习的人一些例子,先看下效果 然后再来看一下我们学校的app 布局分析 先上一张划分好了的布局图 首先整个页面放在一个LinearLayout布局下面,分为上面和下面两个部分,下面一个是显示课程表的详细信息 1:这个没什么好讲的,就是直接一个LinearLayout布局,然后将控件一个TextView用来显示年份,一个View用来当作竖线,一个Spinner用来显示选择周数 2:这个是显示星期几的部件,是我自定义的V