Android 开发过程中的异常奔溃处理

开发过程中捕获异常并定位问题解决问题是基本之一,当然也有很多第三方的平台,比如接入友盟统计、第三方加固(比如360加固等)、腾讯Bugly等都会为我们收集到异常日志。但是,我个人认为开发及测试过程中编写一个Crash收集工具类尤为重要。下面分享一下我的crash处理。直接上代码吧,定义一个CrashHandler工具类
 
 

 
 
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
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 static android.content.ContentValues.TAG;

/**
 * 统一错误捕获类
 * Created by p on 2018/5/16.
 */

public class CrashHandler implements Thread.UncaughtExceptionHandler {
    private Context mContext;
    // CrashHandler实例
    private volatile static CrashHandler instance;
    //系统默认的UncaughtException处理类   
    private Thread.UncaughtExceptionHandler mDefaultHandler;
    //用来存储设备信息和异常信息  
    private Map<String, String> infoMap = new HashMap<String, String>();

    private CrashHandler(Context context) {
        mContext = context.getApplicationContext();
    }

    /**
     * 单利模式 保证对象唯一
     * @param context
     * @return
     */
    public static CrashHandler getInstance(Context context) {
        if (instance == null) {
            synchronized (CrashHandler.class) {
                if (instance == null) {
                    if (context == null) {
                        throw new NullPointerException("context cannet NULL");
                    }
                    instance = new CrashHandler(context);
                }
            }
        }
        return instance;
    }

    public void init() {
        //获取系统默认的UncaughtException处理器  
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        //设置该CrashHandler为程序的默认处理器  
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        if (!handleException(e) && mDefaultHandler != null) {
            //如果用户没有处理则让系统默认的异常处理器来处理  
            mDefaultHandler.uncaughtException(t, e);
        } else {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException ie) {
                log("error : "+ ie);
            }
            //退出程序  
            android.os.Process.killProcess(android.os.Process.myPid());
            System.exit(1);
        }
    }

    /**
     * 处理异常
     * @param e
     * @return
     */
    private boolean handleException(Throwable e) {
        if (e == null) return false;
        new Thread() {
            @Override
            public void run() {
                Looper.prepare();
                Toast.makeText(mContext, "程序出错退出", Toast.LENGTH_LONG).show();
                Looper.loop();
            }
        }.start();
        collectDeviceInfo();
        saveCrashInfo(e);
        return true;
    }

    /**
     * 收集设备参数信息
     */
    private void collectDeviceInfo() {
        try {
            PackageManager pm = mContext.getPackageManager();// 获得包管理器
            PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(),
                    PackageManager.GET_ACTIVITIES);// 得到该应用的信息,即主Activity
            if (pi != null) {
                String versionName = pi.versionName == null ? "null" : pi.versionName;
                String versionCode = pi.versionCode + "";
                infoMap.put("versionName", versionName);
                infoMap.put("versionCode", versionCode);
            }
            //遍历所有Build中的字段
            Field[] fields = Build.class.getDeclaredFields();
            for (Field field : fields){
                infoMap.put(field.getName(),field.get(null).toString());
                log(field.getName()+" : "+field.get(null).toString());
            }
        } catch (Exception e) {
            log(e.getMessage());
        }
    }

    /**
     * 保存日志到SDk
     * @param ex
     */
    private void saveCrashInfo(Throwable ex){
        StringBuilder sb = new StringBuilder();
        sb.append("******************** 手机设备信息 ********************" + "\r\n");
        for (Map.Entry<String,String> entry : infoMap.entrySet()){
            String key = entry.getKey();
            String value = entry.getValue();
            sb.append(key + " = " + value + "\r\n");
        }
        Writer writer = new StringWriter();
        PrintWriter pw = new PrintWriter(writer);
        ex.printStackTrace(pw);
        Throwable cause = ex.getCause();
        // 循环着把所有的异常信息写入writer中
        while (cause != null) {
            cause.printStackTrace(pw);
            cause = cause.getCause();
        }
        pw.close();// 记得关闭
        String result = writer.toString();
        sb.append("******************** 发生崩溃异常信息 ********************" + "\r\n");
        sb.append(result);
        log(result);

        try {
            long timestamp = System.currentTimeMillis();
            DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
            String time = formatter.format(new Date()); String fileName = "crash-" + time + "-"+
            timestamp + ".log";
            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
                String path = "/sdcard/crash/yyf/";
                File dir = new File(path);
                if (!dir.exists()){
                    dir.mkdirs();
                }
                FileOutputStream fos = new FileOutputStream(path + fileName);
                fos.write(sb.toString().getBytes());
                fos.close();
            }
        }catch (Exception e){
            Log.e(TAG,"an error occured while writing file...",e);
        }
    }

    private void log(String msg){
        Log.e(CrashHandler.class.getSimpleName(),msg);
    }
}

Util工具写完,那么说一下我在Application中的处理
1、定义一下debug判断
private static Boolean mDebug = null;

    public static boolean isDebug(){
        return mDebug == null ? false:mDebug.booleanValue();
    }

    private static void syncDebug(Context context){
        if (mDebug == null){
            mDebug = context.getApplicationInfo() != null && (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
        }
    }

2、然后就可以直接在Application的onCreate()方法中调用我们的CrashHandler捕获异常工具类啦

if (isDebug()) {//debug情况下使用
       //系统错误捕获
       CrashHandler.getInstance(this).init();
 }
ok这样就写完了,出现异常崩溃去手机的SD卡找日志分析问题去吧

猜你喜欢

转载自blog.csdn.net/weixin_40929353/article/details/80360666