android UncaughtExceptionHandler全局异常处理

   在编写android客户端应用时,总会由于各种各样的原因,导致我们的程序异常退出,这些原因包括:程序的不合理,异常的未捕获,这些通过我们的review都是可以提高的,但是如果是由于android不同的系统版本,不同的配置的机型导致我们的程序异常退出,这是无法避免的,但如何才能减少这个原因导致的程序异常呢,这正是写本篇文章的意图.

  在全局异常处理开始前,有两个类是我们必须要知道的,一个是android的Application类,这个类是一个应用程序的全局类,可以将一些所有模块都会用的公共信息都放在这个类中初始化,例如:用户登陆信息,手机信息等,一个应用程序的启动最先启动的就是其对应的Application类的实例,然后再由这个实例去调用要启动的那个Activity,另一个就是全局异常捕获类:Thread.UncaughtExceptionHandler,线程未捕获异常处理器,用来处理未捕获异常。如果程序出现了未捕获异常,默认会弹出系统中强制关闭对话框。我们需要实现此接口,并注册为程序中默认未捕获异常处理。这样当未捕获异常发生时,就可以定制异常处理操作,例如:将异常信息存放到SD卡文件中,将应用程序强制关闭,上传错误的日志文件等.

   一般情况下出现这种异常的原因有以下几点:

  1.应用的兼容性欠缺,不过这个孔明 没有办法的事件,android手机千差万别,不同的硬件配置,不同的的手机尺寸,不同的系统版本,所以难免会有考虑不周全的地方.

  2.编写程序时使用了高版本的API,这样当应用跑到低版本的android系统时自然会有异常发生.

  第二种情况是我们在写代码时可以尽量避免的,那就是如果用到了高版本的API,那一定要针对低版本的系统去做处理,这样就可减少这个原因产生的异常.那对于第一种情况怎么办呢,就要用到我们今天的主角,全局异常捕获了.

  当APP异常退出时,这部分异常信息是可以通过全局异常处理机制捕获到的,一旦捕获到后,就可以上传到我们的文件服务器中,去做分析,针对性的改进,这就是全局异常处理最主要的作用.

   全局异常示例代码:


/**********************************************************
 * @文件名称:MicCrashHandler.java
 * @创建时间:2014年10月20日 下午1:10:15
 * @文件描述:捕获全局未处理到的异常,上传服务器
 * @修改历史:2014年10月20日创建初始版本
 **********************************************************/
public class MicCrashHandler implements UncaughtExceptionHandler
{
    public static final String TAG = "MicCrashHandler";
    /**
     * 系统默认的异常捕获类
     */
    private Thread.UncaughtExceptionHandler mDefaultHandler;

    /**
     * 自定义异常处理类
     */
    private static MicCrashHandler INSTANCE;

    private Context mContext;
    /**
     * 存储异常信息
     */
    private HashMap<String, String> infos = new HashMap<String, String>();
    // 存储文件夹路径
    private static final String path = Environment.getExternalStorageDirectory() + "/focustech/mic/log/";
    private File dirFile;
    private File file;
    private static final String fileName = "mic_crash_exception.log";

    private MicCrashHandler()
    {
    }

    static
    {
        INSTANCE = new MicCrashHandler();
    }

    /**
     * 单例模式,获取自定义异常处理类
     */
    public static MicCrashHandler getInstance()
    {
        return INSTANCE;
    }

    public void init(Context context)
    {
        mContext = context;
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    /**
     * 
     * 自定义异常处理
     * @param thread
     * @param ex
     */
    @Override
    public void uncaughtException(Thread thread, Throwable ex)
    {

        if (!handleException(ex) && mDefaultHandler != null)
        {
            // 如果用户没有处理则让系统默认的异常处理器来处理
            mDefaultHandler.uncaughtException(thread, ex);
        }
        else
        {

        }
    }

    /**
     * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
     */
    private boolean handleException(Throwable ex)
    {
        if (ex == null)
        {
            return false;
        }

        new Thread()
        {
            @Override
            public void run()
            {
                Looper.prepare();
                ToastUtil.toast(mContext, R.string.crash_exception);
                Looper.loop();
            }
        }.start();

        // 收集设备参数信息
        Util.collectDeviceInfo(mContext, infos);
        // 保存日志文件
        saveCrashInfo2File(ex);
        /**
         * 以后要加上传功能,需要启动服务去上传应该
         */
        // uploadExceptionFile();
        ActivityManager.getInstance().finishAllActivity();
        Process.killProcess(Process.myPid());
        System.exit(0);
        return true;
    }

    /**
     * 保存错误信息到文件中
     * @param ex
     * @return    返回文件名称,便于将文件传送到服务器
     */
    private void saveCrashInfo2File(Throwable ex)
    {
        /**
         * 组装异常信息
         */
        String exceptionMsg = assembleExceptionMsg(ex);
        try
        {
            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
            {
                dirFile = new File(path);
                if (!dirFile.exists())
                {
                    dirFile.mkdirs();
                }

                file = new File(path + fileName);
                RandomAccessFile fos = new RandomAccessFile(file, "rw");
                fos.seek(file.length());
                fos.write(exceptionMsg.getBytes());
                fos.close();
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    /**
     * 组装异常信息,在这里拼装想要的格式
     */
    private String assembleExceptionMsg(Throwable ex)
    {
        StringBuffer sb = new StringBuffer();
        for (Map.Entry<String, String> entry : infos.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();
        while (cause != null)
        {
            cause.printStackTrace(printWriter);
            cause = cause.getCause();
        }
        printWriter.close();
        String result = writer.toString();
        sb.append(result + "\r\n");

        return sb.toString();
    }

    /**
     * 发送上传文件请求
     */
    @SuppressWarnings("unused")
    private void uploadExceptionFile()
    {

        if (!NetworkUtils.isConnectInternet(mContext))
        {
            return;
        }
        if (file == null || !file.exists())
        {
            return;
        }
        else
        {
            RequestCenter.uploadExceptionFile(mContext, listener, file);
        }
    }

    private DisposeDataListener listener = new DisposeDataListener()
    {
        @Override
        public void onSuccess(Object obj)
        {
            /**
             * 发送成功后,还要删除此异常文件,才退出            
             */
            SysManager.exitSystem(mContext);
        }

        @Override
        public void onFailure(Object failedReason)
        {
            SysManager.exitSystem(mContext);
        }
    };
}




  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值