Android开发之处理崩溃异常

众所周知,android的设备千差万别,难免会发生崩溃异常等现象,这个时候就需要捕获哪些崩溃异常了,也就是捕获崩溃异常的相关信息,并记录下来,这样一来方便开发人员和测试人员的分析与调试。

1.首先我们得创建一个处理崩溃异常的类,暂且命名为:CrashHandler吧。实现如下:

 
import java.io.File;
import java.io.FileOutputStream;
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.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Looper;
import android.sax.StartElementListener;
import android.util.Log;
import android.widget.Toast;

/**
 * UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告到log文件中.
 *
 * @author caizhiming
 */
public class CrashHandler implements UncaughtExceptionHandler {

    public static final String TAG = "CrashHandler";

    // 系统默认的UncaughtException处理类
    private Thread.UncaughtExceptionHandler mDefaultHandler;
    // CrashHandler实例
    private static CrashHandler INSTANCE = new CrashHandler();
    // 程序的Context对象
    private Context mContext;
    // 用来存储设备信息和异常信息
    private Map<String, String> infos = new HashMap<String, String>();

    // 用于格式化日期,作为日志文件名的一部分
    private SimpleDateFormat formatter;

    /**
     * 保证只有一个CrashHandler实例
     */
    private CrashHandler() {
    }

    /**
     * 获取CrashHandler实例 ,单例模式
     */
    public static CrashHandler getInstance() {
        return INSTANCE;
    }

    /**
     * 初始化
     *
     * @param context
     */
    public void init(Context context) {
        mContext = context;
        // 获取系统默认的UncaughtException处理器
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        // 设置该CrashHandler为程序的默认处理器
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    /**
     * 当UncaughtException发生时会转入该函数来处理
     */
    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        if (!handleException(ex) && mDefaultHandler != null) {
            // 如果用户没有处理则让系统默认的异常处理器来处理
            mDefaultHandler.uncaughtException(thread, ex);
        } else {
            // 退出程序
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            android.os.Process.killProcess(android.os.Process.myPid());
            System.exit(1);
        }
    }

    /**
     * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
     *
     * @param ex
     * @return true:如果处理了该异常信息;否则返回false.
     */
    private boolean handleException(final Throwable ex) {
        if (ex == null) {
            return false;
        }

//        Intent showcrashDLg = new Intent(mContext,CrashActivity.class);
//        mContext.startActivity(showcrashDLg);

        ex.printStackTrace();
        // 使用Toast来显示异常信息

        // 收集设备参数信息
        collectDeviceInfo(mContext);

        // 保存日志文件
        saveCrashInfoToFile(ex);

        return true;
    }

    /**
     * 收集设备参数信息
     *
     * @param ctx
     */
    public void collectDeviceInfo(Context ctx) {
        try {
            PackageManager pm = ctx.getPackageManager();
            PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(),
                    PackageManager.GET_ACTIVITIES);
            if (pi != null) {
                String versionName = pi.versionName == null ? "null"
                        : pi.versionName;
                String versionCode = pi.versionCode + "";
                infos.put("versionName", versionName);
                infos.put("versionCode", versionCode);
            }
        } catch (NameNotFoundException e) {
            Log.e(TAG, "an error occured when collect package info", e);
        }
        Field[] fields = Build.class.getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                infos.put(field.getName(), field.get(null).toString());
                Log.d(TAG, field.getName() + " : " + field.get(null));
            } catch (Exception e) {
                Log.e(TAG, "an error occured when collect crash info", e);
            }
        }
    }

    /**
     * 保存错误信息到文件中
     *
     * @param ex
     * @return 错误崩溃信息写到log文件中
     */
    private void saveCrashInfoToFile(Throwable ex) {
        StringBuffer sb = new StringBuffer();
        sb.append("==============================Crash happened at Time:"
                + CommonUtils.getCurTime()
                + "==============================\r\n");
        for (Map.Entry<String, String> entry : infos.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            sb.append(key + "=" + value + "\r\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);
        try {
            LogCore.addLog(sb.toString());

        } catch (Exception e) {
            Log.e(TAG, "an error occured while writing file...", e);
        }
        Analyse.uplodcrash(sb.toString());

    }

    /**
     * 用Dialog显示错误信息
     *
     * @param ex
     * @return 用Dialog显示错误信息
     */
    private void showCrashInfoDialog(Throwable ex) {

        StringBuffer sb = new StringBuffer();

        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);
        try {
            // DlgUtils.ShowDialog(mContext,"程序崩溃了");
            // LogCore.d(mContext,sb.toString());
            AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
            builder.setTitle("程序崩溃啦~");
            builder.setMessage(sb.toString());
            builder.setPositiveButton("我知道了", new OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    // TODO Auto-generated method stub
                    android.os.Process.killProcess(android.os.Process.myPid());
                    System.exit(1);
                }
            });
//            builder.create().show();
        } catch (Exception e) {
            Log.e(TAG, "an error occured while writing file...", e);
        }
    }

}

2.完成这个CrashHandler后,我们需要在一个Application环境中让其运行,为此,我们继承android.app.Application,添加自己的代码,CrashApplication.java代码如下:

package com.czm.crash;  

import android.app.Application;  

public class CrashApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        CrashHandler crashHandler = CrashHandler.getInstance();
        crashHandler.init(getApplicationContext());
    }
}  

3.除此之外,最后,为了让上面的CrashApplication取代android.app.Application的地位,在我们的代码中生效,我们需要修改AndroidManifest.xml:

<application android:name=".CrashApplication" ...>
</application> 

Android开发之处理崩溃异常

时间: 2024-12-15 08:13:33

Android开发之处理崩溃异常的相关文章

Android开发-新建线程崩溃

一直不满意车机不能实现屏保,最近发现可以通过设置亮度实现,顾萌生了自己写程序的来实现的念头,遂修改原来练手的app.毕竟过去了1年,各类程序.sdk都已经更新了不知道多少版本.经历了痛苦的升级.更新,终于没能在原有的代码上直接升级,还是新建一个工程,复制原来的代码来生成app. 原来可以跑的app,竟然崩溃,而且还不能截获异常.通过debug,发现崩溃跟新建了一个线程有关,网上度了一下,发现还是能够捕获此类异常,原文:Android UncaughtExceptionHandler捕获线程崩溃异

android开发 不留言的异常

最近刚上班,做了一个应用,要上线,测试天天测试,天天有bug,个人总结了几个经常忽略的地方: 1:在 继承 BaseAdapter 的 @Override public int getCount() { <span style="color:#ff0000;">return list == null ? 0 : list.size();</span> } 这里尽量这样写,不然有时会出现空指针异常的 总结写程序要:严谨 android开发 不留言的异常

android开发 不注意的异常

近期刚上班,做了一个应用,要上线.測试天天測试,天天有bug,个人总结了几个常常忽略的地方: 1:在 继承 BaseAdapter 的 @Override public int getCount() { <span style="color:#ff0000;">return list == null ? 0 : list.size();</span> } 这里尽量这样写.不然有时会出现空指针异常的 总结敲代码要:严谨

Android中处理崩溃异常CrashHandler

来源:http://blog.csdn.net/liuhe688/article/details/6584143 大家都知道,现在安装Android系统的手机版本和设备千差万别,在模拟器上运行良好的程序安装到某款手机上说不定就出现崩溃的现象,开发者个人不可能购买所有设备逐个调试,所以在程序发布出去之后,如果出现了崩溃现象,开发者应该及时获取在该设备上导致崩溃的信息,这对于下一个版本的bug修复帮助极大,所以今天就来介绍一下如何在程序崩溃的情况下收集相关的设备参数信息和具体的异常信息,并发送这些信

android开发异常信息收集程序代码

首先创建全局的Application ,此Application全局通用. package com.demo.utils; import com.demo.exception.CrashHandler; import android.app.Application; /** * 全局的context,任意位置调用 * @author Administrator * */ public class GlobalApplication extends Application { private st

Android开发配置,消除SDK更新时的“https://dl-ssl.google.com refused”异常

消除SDK更新时的“https://dl-ssl.google.com refused”错误 消除SDK更新时,有可能会出现这样的错误:Download interrupted: hostname in certificate didn't match: <dl-ssl.google.com> != <www.google.com>Download interrupted: Connection to https://dl-ssl.google.com refusedDone. N

Android程序崩溃异常收集框架

最近在写Android程序崩溃异常处理,完成之后,稍加封装与大家分享. 我的思路是这样的,在程序崩溃之后,将异常信息保存到一个日志文件中,然后对该文件进行处理,比如发送到邮箱,或发送到服务器. 所以,第一步是先定义一个接口,用于在保存好日志之后的回调.代码如下: /* * @(#)CrashListener.java Project: crash * Date:2014-5-27 * * Copyright (c) 2014 CFuture09, Institute of Software, *

Android开发遇到的异常及解决办法

Android开发遇到的错误及解决方法1. Unable to resolve target 'android-7' 解决方案: 修改工程目录下的default.properties文件里的内容target=android-7改成target=android-12(或者其他版本)就可以了,最好用txt打开,然后修改之后保存,运行就可以了. 原代码如下: # This file is automatically generated by Android Tools.# Do not modify

Android开发中关于Movie导入GIF图片异常的问题

下面麦子学院来给各位同学介绍一篇关于Android开发中关于Movie导入播放GIF图片文件异常IOException.reset的解决办法,希望些方法对你有帮助. 使用Movie播放GIF图片时,能正常导入assets中的gif文件,如: 代码如下 is=context.getResources().openRawResource(R.drawable.mygif); movie =Movie.decodeStream(is); 然而把网络图片加载到本地后,却报以下错误: 代码如下 java.