Android之全局异常处理

最近遇到一个问题,app遇到异常就崩溃了,断点也打不到,日志也被刷掉了,看不到异常消息处理不了异常,没有集成第三方工具。
想了做个全局异常类CrashHandler,处理全局异常:
此类不能与google的firebase 、crashlytics一块使用,
使用方法在MyApplication的onCreate中初始化一下,就ok

public class MyApplication extends Application {

    private static final String TAG = "MyApplication";
    
    @Override
    public void onCreate() {
        super.onCreate();
        /**全局异常捕捉*/
        CrashHandler.getInstance().init(this);
    }
}
/**
 * 全局异常捕捉,日志文件保存在android/data/app报名/cache目录中
 */
public class CrashHandler implements UncaughtExceptionHandler {

    /**
     * TAG
     */
    private static final String TAG = "CrashHandler";

    /**
     * uploadUrl 服务器的地址,根据自己的情况进行更改
     */
    private static final String uploadUrl = "http://3.saymagic.sinaapp.com/ReceiveCrash.php";
    /**
     * localFileUrl 本地log文件的存放地址
     */
    private static String localFileUrl = "";
    /**
     * instance
     */
    private volatile static CrashHandler instance;
    /**
     * mDefaultHandler
     */
    private UncaughtExceptionHandler defaultHandler;
    /**
     * infos
     */
    private Map<String, String> infos = new HashMap<>();

    /**
     * formatter
     */
    private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * context
     */
    private Context context;

    private CrashHandler() {
    }

    public static CrashHandler getInstance() {
        if (instance == null) {
            synchronized (CrashHandler.class) {
                if (instance == null) {
                    instance = new CrashHandler();
                }
            }
        }
        return instance;
    }

    /**
     * @param ctx 初始化,此处最好在Application的OnCreate方法里来进行调用
     */
    public void init(Context ctx) {
        this.context = ctx;
        defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    /**
     * uncaughtException 在这里处理为捕获的Exception
     */
    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {
        if(!handleException(throwable)) {
            if (defaultHandler != null) {
                defaultHandler.uncaughtException(thread, throwable);
            }
        }

        // 退出程序
        android.os.Process.killProcess(android.os.Process.myPid());
    }

    private boolean handleException(Throwable ex) {
        if (ex == null) {
            return false;
        }
        Log.d("TAG", "收到崩溃");

        collectDeviceInfo(context);
        writeCrashInfoToFile(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);
                infos.put("crashTime", formatter.format(new Date()));
            }
        } catch (NameNotFoundException 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) {
            }
        }
    }

    /**
     * @param ex 将崩溃写入文件系统
     */
    private void writeCrashInfoToFile(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);

        //上传到umeng
        //MobclickAgent.reportError(context, sb.toString());

        //这里把刚才异常堆栈信息写入SD卡的Log日志里面
        String filePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/crash/";
        localFileUrl = writeLog(sb.toString(), filePath);
    }

    /**
     * @param log
     * @param name
     * @return 返回写入的文件路径 写入Log信息的方法,写入到SD卡里面
     */
    private String writeLog(String log, String name) {
        SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date = sDateFormat.format(new Date());
        String filename = name + "crash" + date + ".log";

        File file = new File(filename);
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        try {
            file.createNewFile();
            FileWriter fw = new FileWriter(file, true);
            BufferedWriter bw = new BufferedWriter(fw);
            //写入相关Log到文件
            bw.write(log);
            bw.newLine();
            bw.close();
            fw.close();
            return filename;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    private void restart() {

        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
        } finally {
            Context appContext = context.getApplicationContext();
            Intent intent = appContext.getPackageManager().getLaunchIntentForPackage(appContext.getPackageName());
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
            PendingIntent restartIntent = PendingIntent.getActivity(appContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
            AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
            mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent);
            System.exit(0);
        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值