Android全局异常捕获,解决日志打印三次的BUG

最近写的项目需要自己写全局的异常捕捉,所以百度了很多解决方案,发现出现各种问题,好不容易找到一些比较靠谱的方案,但是却发现出现了一个让我无语的问题——日志打印输出三次。于是又开始去寻找答案,发现并没有相关的解决。好嘛,看来还是要自己搞了。

发生该现象的基本原因就是:Application没有完全退出,导致同一个异常多次执行,于是出现了同一个异常打印多次的问题


【解决方案】

  • 处理全局异常的Handler:CrashHandler.java,代码如下:
public class CrashHandler implements UncaughtExceptionHandler {
    private static CrashHandler instance;
    private UncaughtExceptionHandler mDefaultHandler;

    public void init(Context ctx) {
        Thread.setDefaultUncaughtExceptionHandler(this);
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();// 获取系统默认的UncaughtException处理器

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

    /**
     * 核心方法,当程序crash 会回调此方法, Throwable中存放这错误日志
     */
    @Override
    public synchronized void uncaughtException(Thread arg0, Throwable arg1) {
        if (mDefaultHandler != null && !handleException(arg1)) {
            // 如果自定义的没有处理则让系统默认的异常处理器来处理
            mDefaultHandler.uncaughtException(arg0, arg1);
        } else {
            // 退出程序
            try {
                Thread.sleep(3000);// 如果处理了,让程序继续运行3秒再退出,保证文件保存并上传到服务器
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Myapplication.getApplication().closeApplication();//完全退出Application
//          如果使用如下方法退出程序,将会发生日志打印三次的BUG
//          android.os.Process.killProcess(android.os.Process.myPid());
//          System.exit(1);
        }
    }

    private boolean handleException(Throwable arg1) {
        String logPath;
        if (Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) {
            logPath = Environment.getExternalStorageDirectory()
                    .getAbsolutePath()
                    + File.separator
                    + File.separator
                    + "log";
            File file = new File(logPath);
            if (!file.exists()) {
                file.mkdirs();
            }
            try {
                FileWriter fw = new FileWriter(logPath + File.separator
                        + CommonUtil.getStrTime() + ".log", false);
                StringBuffer sb = new StringBuffer();
                sb.append("/*************************************************/\n");
                sb.append(new Date() + "\n");
                // 错误信息
                // 这里还可以加上当前的系统版本,机型型号 等等信息
                StackTraceElement[] stackTrace = arg1.getStackTrace();
                sb.append("错误信息:" + arg1.getMessage() + "\n");
                for (int i = 0; i < stackTrace.length; i++) {
                    String info = "文件:" + stackTrace[i].getFileName() + "   类:"
                            + stackTrace[i].getClassName() + "   方法:"
                            + stackTrace[i].getMethodName() + "   行号:"
                            + stackTrace[i].getLineNumber() + "\n";
                    sb.append(info);
                }
                sb.append("/*************************************************/\n");
                fw.write(sb.toString());
                fw.close();
                // 上传错误信息到服务器
                uploadToServer(sb);
            } catch (IOException e) {
                Log.e("crash handler", "load file failed...", e.getCause());
            }
        }
        return true;
    }

    private void uploadToServer(StringBuffer sb) {
        //执行上传操作,错误信息为:sb.toString();
    }

}
  • Handler的初始化以及MyApplication的编写:MyApplication.java
public class Myapplication extends Application {
    private List<Activity> activitys = new LinkedList<Activity>();
    private List<Service> services = new LinkedList<Service>();
    private static int mTid;
    private static Myapplication mApplication;
    private CrashHandler crashHandler;

    @Override
    public void onCreate() {
        super.onCreate();
        mApplication = this;
        mTid = android.os.Process.myTid();
        crashHandler = CrashHandler.getInstance();
        crashHandler.init(getApplicationContext());
    }

    /**
     * 
     * TODO 获取活动队列
     */
    public List<Activity> getActivitys() {
        return activitys;
    }

    /**
     * 
     * TODO 添加Activity
     */
    public void addActivity(Activity activity) {
        activitys.add(activity);
    }

    /**
     * 
     * TODO 移除Activity
     */
    public void removeActivity(Activity activity) {
        activitys.remove(activity);
    }

    /**
     * 
     * TODO 添加服务
     */
    public void addService(Service service) {
        services.add(service);
    }

    /**
     * 
     * TODO 移除Service
     */
    public void removeService(Service service) {
        services.remove(service);
    }

    /**
     * 
     * TODO 关闭程序
     */
    public void closeApplication() {
        closeActivitys();
        closeServices();
        android.os.Process.killProcess(android.os.Process.myPid());
    }

    /**
     * 
     * TODO 关闭所有的Activity
     */
    public void closeActivitys() {
        ListIterator<Activity> iterator = activitys.listIterator();
        while (iterator.hasNext()) {
            Activity activity = iterator.next();
            if (activity != null) {
                activity.finish();
            }
        }
    }

    /**
     * 
     * TODO 关闭所有的Service
     */
    private void closeServices() {
        ListIterator<Service> iterator = services.listIterator();
        while (iterator.hasNext()) {
            Service service = iterator.next();
            if (service != null) {
                stopService(new Intent(this, service.getClass()));
            }
        }
    }


    /**
     * 
     * TODO 获取Application
     */
    public static Myapplication getApplication() {
        return mApplication;
    }

    /**
     * 
     * TODO 获取主线程PID
     */
    public static int getmTid() {
        return mTid;
    }

}
  • BaseActivity的编写:BaseActivity.java
public class BaseActivity extends Activity {
    protected BaseActivity mActivity;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);// 保存生命周期的完整性
        ((Myapplication) getApplication()).addActivity(this);
        mActivity = this;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        ((Myapplication) getApplication()).removeActivity(this);
    }
}

总结

以上代码仅供参考,可能有更好的解决方法,欢迎大家给我留言。本人Android菜鸟一枚,并非大牛,可能部分代码不尽如人意,希望各位大大可以予以指出,我会虚心接受并积极改正,谢谢大家!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值