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开发)