Android崩溃处理

当程序FC时,系统会调用Thread中的接口UncaughtExceptionHandler,调用 uncaughtException(Thread thread, Throwable ex)方法,所以,我们可以实现自己的UncaughtExceptionHandler,实现uncaughtException方法,设置:
Thead.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler handler)
以此来对崩溃进行处理

在uncaughtException中,做了以下3件事

1.崩溃时的回调
2.收集设备信息与崩溃堆栈信息
3.重启应用

当再次启动应用时,若发现log日志中有内容,可以上传至服务器

public class CrashHandler implements Thread.UncaughtExceptionHandler {

    private static CrashHandler mInstance;
    private Context mContext;
    private Class mRestartClass;//崩溃后,重启软件时的Activity,可设置为反馈界面
    private OnCrashListener mListener;
    private String mLogPath;//崩溃日志的储存路径

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

    public static void registCrashHandler(Context context, String logPath,Class restartActivity, OnCrashListener listener) {
        if (mInstance == null) {
            synchronized (CrashHandler.class) {
                if (mInstance == null) {
                    mInstance = new CrashHandler(context);
                    mInstance.setRestartClass(restartActivity);
                    mInstance.setOnCrashListener(listener);
                    mInstance.setLogPath(logPath);
                    Thread.setDefaultUncaughtExceptionHandler(mInstance);//设置自定义的UncaughtExceptionHandler
                }
            }
        }
    }


    public void setRestartClass(Class restartActivity) {
        mRestartClass = restartActivity;
    }


    public void setLogPath(String path){
        mLogPath = path;
    }

    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        try {
            if (mListener != null) {
                mListener.onCrashBegin();
            }

            File logFile = new File(mLogPath);
            if(!logFile.getParentFile().exists()){
                logFile.getParentFile().mkdirs();
            }

        //文本的格式可自行调整
            FileWriter fw = new FileWriter(logFile, true);
            BufferedWriter bw = new BufferedWriter(fw);
            bw.write("\n#####################\n");
            bw.write("crashedTime=" + getNowTimeString() + "\n");
            HashMap<String, String> deviceInfo = getDeviceInfo();
            //保存设备信息
            for (HashMap.Entry<String, String> entry : deviceInfo.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                bw.write(key + "=" + value + "\n");
            }
            //保存堆栈信息
            bw.write("\n###message###\n");
            bw.write(ex.getMessage() + "\n");
            bw.write("\n###StackTrace###\n");
            final StackTraceElement[] stack = ex.getStackTrace();
            for (StackTraceElement ele : stack) {
                bw.write(ele.toString() + "\n");
            }
            bw.flush();
            fw.flush();
            bw.close();
            fw.close();
            //Thread.sleep(100);若回调中某些操作需要一些时间,可以sleep一下
        } catch (Exception e) {
            e.printStackTrace();
        }

        restart();
        android.os.Process.killProcess(android.os.Process.myPid());
        System.exit(1);
    }

    //收集设备信息
    private HashMap<String, String> getDeviceInfo() {
        HashMap<String, String> map = new HashMap<>();
        try {
            PackageManager pm = mContext.getPackageManager();
            PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(),
                    PackageManager.GET_ACTIVITIES);
            String versionName = pi.versionName == null ? "null" : pi.versionName;
            String versionCode = pi.versionCode + "";
            map.put("versionName", versionName);
            map.put("versionCode", versionCode);
            map.put("build.version.release", Build.VERSION.RELEASE);
            map.put("build.version.sdk", "" + Build.VERSION.SDK_INT);
            map.put("build.model", Build.MODEL);
            map.put("build.manufacturer", Build.MANUFACTURER);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return map;
    }


    private String getNowTimeString() {
        Calendar calendar = Calendar.getInstance();
        String pattern = "yyyy_MM_dd_HH_mm";
        SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.getDefault());
        return sdf.format(calendar.getTime());
    }

    //重新启动
    private boolean restart() {
        try {
            if (mRestartClass == null) {
                return false;
            }
            Intent intent = new Intent(mContext.getApplicationContext(),
                    CrashRestartReceiver.class);
            intent.putExtra("RESTART_CLASS", mRestartClass);
            PendingIntent pI = PendingIntent.getBroadcast(mContext.getApplicationContext(),
                    0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
            AlarmManager mgr = (AlarmManager) (mContext.getSystemService(Context.ALARM_SERVICE));
            mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, pI); // 0.1秒钟后重启应用
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public interface OnCrashListener {
        void onCrashBegin();
    }

    public void setOnCrashListener(OnCrashListener listener) {
        this.mListener = listener;
    }
}

重启应用的BroadcastReceiver

public class CrashRestartReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Class restartClass = (Class) intent.getSerializableExtra("RESTART_CLASS");
        Intent newIntent = new Intent(context, restartClass);
        newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(newIntent);
    }
}

在Application的onCreate方法中,调用:
CrashHandler.registCrashHandler(Context context, String logPath,Class restartActivity, OnCrashListener listener) 方法
并且静态注册CrashRestartReceiver

猜你喜欢

转载自blog.csdn.net/u013531215/article/details/46045621