程序员

奔溃捕获

2018-10-18  本文已影响0人  lipyhui

一、说明

  笔记主要是记录一些本人在开发当中的学习和使用笔记。笔记内容包含一些本人觉得重要的知识点、本人易犯的错误等。
  由于本人水平有限,其中出现的错误或者不合理的地方望各位读者多多包含,并指出其中不合理和错误的地方,以便我来修正。谢谢!

二、笔记时间

  2018年10月17日

三、简述

  本文主要讲述Android APP为什么需要奔溃捕获和奔溃捕获的方式。

四、详情

1、简介

  在开发Android APP当中,难免会有一些无法预期的错误,或者在特殊环境下和操作下才会出现的错误。当这些错误发生时,会导致APP奔溃并且出现不友好的界面,影响APP的体验。
  那么我们程序员GG怎么解决这些错误,还给用户一个体验完美的APP呢?这个时候奔溃捕获的作用就体现出来了,我们通过奔溃捕获获取奔溃日志,并把奔溃日志保存到本地或者发送到日志服务器,以便程序员GG来查看和解决错误。

2、奔溃捕获示例

2.1、实现UncaughtExceptionHandler

//CrashHandler.java
package com.lipy.demo.crashhandler;

import android.app.AlarmManager;
import android.app.Application;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.io.StringWriter;
import java.io.Writer;
import java.text.SimpleDateFormat;

/**
 * 创建人: lipy
 * 创建时间: 2017/8/4
 * 修改人:lipy
 * 修改时间:2017/8/4
 * 修改内容:
 *
 * 功能描述:捕获奔溃并重启
 */
public class CrashHandler implements Thread.UncaughtExceptionHandler {
    private final String PATH = "/storage/sdcard0/crash_logger.txt";

    public static CrashHandler mAppCrashHandler;

    private Thread.UncaughtExceptionHandler mDefaultHandler;

    private Application mAppContext;

    public static CrashHandler getInstance() {
        if (mAppCrashHandler == null) {
            mAppCrashHandler = new CrashHandler();
        }
        return mAppCrashHandler;
    }

    public void initCrashHandler(Application application) {
        this.mAppContext = application;
        // 获取系统默认的UncaughtException处理器
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        if (!handleException(ex) && mDefaultHandler != null) {
            // 如果用户没有处理则让系统默认的异常处理器来处理
            //mDefaultHandler.uncaughtException(thread, ex);
        }

        //设置重启定时器
        AlarmManager mgr = (AlarmManager) mAppContext.getSystemService(Context.ALARM_SERVICE);

        //1秒后重启
        Intent intent = new Intent(mAppContext, MainActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        PendingIntent restartIntent = PendingIntent.getActivity(mAppContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
        mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent); // 1秒钟后重启应用

        //杀死进程
        android.os.Process.killProcess(android.os.Process.myPid());
        System.exit(0);
        System.gc();
    }

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

        //收集奔溃日志
        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();

        //保存日志
        saveInfo(result);

        // 自定义处理错误信息
        return true;
    }

    /**
     * 保存错误信息到本地文件
     *
     * @param msg String
     */
    private void saveInfo(String msg) {
        try {
            String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(System.currentTimeMillis());
            String info = time + ":\n\r" + msg + "\n\r\n\r";
            RandomAccessFile log = new RandomAccessFile(PATH, "rw");
            log.skipBytes((int) log.length());
            log.write(info.getBytes());
            log.close();
        } catch (Exception e) {
            Log.e("CrashHandler", "save crash info err !!" + e.toString());
        }
    }
}

2.2、自定义Application

//MyApplication.java
package com.lipy.demo.crashhandler;

import android.app.Application;

/**
 * 创建人: lipy
 * 创建时间: 2018/10/18
 * 修改人:lipy
 * 修改时间:2018/10/18
 * 修改内容:
 *
 * 功能描述:自定义Application
 */
public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        //异常捕获初始化
        CrashHandler.getInstance().initCrashHandler(this); // 一定要初始化
    }
}

2.3、注册清单

  在AndroidManifest.xml中注册MyApplication,通过android:name=".MyApplication" 使APP的Application使用自定义的MyApplication。

<application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round">

</application>

  由于中示例的MyApplication中的奔溃日志是保存到本地文件当中,因此需要添加文件读写权限。

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

2.4、示例源码

  示例源码:https://github.com/lipyhui/android_app_demo/tree/master/CrashHandler

上一篇 下一篇

猜你喜欢

热点阅读