Android应用捕获全局异常自定义处理

[2016-06-30]最新的全局异常处理DRCrashHandler已经集成在DR_support_lib库中

具体请看: https://coding.net/u/wrcold520/p/DR_support_lib/git/tree/master

[2016-06-28] 1 增加log4j的支持
[2016-06-28] 2 增加全局异常处理(可自定义程序崩溃提示消息,自定义发送错误报告到服务器)
[2016-06-28] 3 增加两种应用退出方法:① appExit,结束掉所有Acitivity的生命周期,正常退出;② appKill,结束掉所有Acitivity的生命周期,杀掉程序进程后退出。
[2016-06-29] 4 增加透明状态栏和导航栏(默认开启,蓝色背景)

在Android程序中,我们通常会在可能发生错误的地方加上try {} catch (Exception e) {}语句来捕获异常,但是,我们无法保证程序就一定不会出错,比如,你玩Android游戏的过程中经常会碰到黑屏或者直接退出的情况,那么这些异常就应该是没有被捕获到(一般获取到都会提示用户错误,并提示用户是否将错误上传至服务器),那么现在我们来看下如何捕获全局异常,然后自己处理。

1、新建DRCrashHandler.java(这是一个抽象类,我放在了DR_supprot_lib库中,以便以后再写应用程序的时候直接使用,里面用到了一些变量是DRConstants类中的,这是一个常量类,用来定义常用的常量的)

默认Toast弹窗提示用户(消息可以自定义)

package cn.dr.lib.app;

import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import org.apache.log4j.Logger;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Looper;
import android.widget.Toast;
import cn.dr.lib.common.DRConstants;
import cn.dr.lib.utils.DateUtil;
import cn.dr.lib.utils.FileUtil;

/**
 * DarkRanger的全局异常处理类
 * 
 * @author DarkRanger
 *
 */
public abstract class DRCrashHandler implements UncaughtExceptionHandler {

    /** log4j **/
    private static final Logger log = Logger.getLogger(DRCrashHandler.class);

    /** 系统默认的UncaughtException处理类 **/
    private Thread.UncaughtExceptionHandler mDefaultHandler;

    /** 程序context **/
    private DRApplication mContext;

    /** 存储设备信息和异常信息 **/
    private Map<String, String> mInfos = new HashMap<String, String>();

    /** 程序出错提示信息 **/
    private String mDRTipMsg = "抱歉,程序异常,3s后退出!";

    /** 设置crash文件位置 **/
    private String mDRCrashFilePath = DRConstants.CRASH_FILE_PATH;

    /** 生成的log文件 **/
    private File logFile;

    /** 生成的crash文件 **/
    private File crashFile;

    /**
     * 初始化
     * 
     * @param context
     */
    public void init(DRApplication context) {
        log.info("DRCrashHandler is Ready For Application! ");

        // 1、上下文
        mContext = context;

        // 2、获取系统默认的UncaughtException处理器
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();

        // 3、初始化参数
        initParams();

        // 4、设置当前CrashHandler为默认处理异常类
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    /**
     * 3.1 初始化参数 <br/>
     * <br/>
     * 
     * {@link #setTipMsg(String)} setTipMsg("this is crash tip msg!!!"); <br/>
     * {@link #setCrashFilePath(String)}
     * setCrashFilePath(Constants.CRASH_FILE_PATH); <br/>
     * <br/>
     * 
     * 如果想使用自己的CrashHandler,则复写initParams()方,然后设置参数<br/>
     * 
     * <code>
     * public class MyCrashHandler extends DRCrashHandler {<br/>
     *        private static final Logger log = Logger.getLogger(MyCrashHandler.class);<br/>
     *    
     *        &#64;Override<br/>
     *        public void initParams() {<br/>
     *            log.trace("MyCrashHandler: initParams()");<br/>
     *    
     *            setDRTipMsg("MyCrashHandler tip msg!!!");<br/>
     *            setDRCrashFilePath(Constants.CRASH_FILE_PATH);<br/>
     *        }<br/>
     *    }<br/>
     * </code>
     */
    public abstract void initParams();

    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        log.info("DRCrashHandler dispatcher uncaughtException! ");

        if (mDefaultHandler != null && !handlerException(ex)) {
            mDefaultHandler.uncaughtException(thread, ex);
        } else {
            // 程序休眠3s后退出
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            ((DRApplication) mContext.getApplicationContext()).appExit();
        }

    }

    /**
     * 5、处理异常<br>
     * <br>
     * 
     * 5.1 收集设备参数信息<br>
     * 5.2 弹出窗口提示信息<br>
     * 5.3 保存log和crash到文件<br>
     * 5.4 发送log和crash到服务器<br>
     * 
     * @param ex
     * @return 是否处理了异常
     */
    protected boolean handlerException(Throwable ex) {
        log.info("DRCrashHandler is handling Exception! ");

        if (ex == null) {
            return false;
        } else {

            // 5.1 收集设备参数信息
            collectDeviceInfo(mContext);

            // 5.2 弹出窗口提示信息
            new Thread(new Runnable() {
                public void run() {
                    log.info("DRCrashHandler is ready send crash-info to device!");

                    Looper.prepare();
                    Toast.makeText(mContext, getDRTipMsg(), Toast.LENGTH_SHORT).show();
                    Looper.loop();
                }
            }).start();

            // 5.3 保存log和crash到文件
            saveLogAndCrash(ex);
            // 5.4 发送log和crash到服务器
            sendLogAndCrash();

            return true;
        }

    }

    /**
     * 5.1 收集设备信息
     * 
     * @param ctx
     */
    protected void collectDeviceInfo(Context ctx) {
        log.info("DRCrashHandler is collecting DeviceInfo! ");

        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 + "";
                mInfos.put("versionName", versionName);
                mInfos.put("versionCode", versionCode);
            }
        } catch (NameNotFoundException e) {
            log.error("An error occured when collect package info, Error: " + e);
        }
        Field[] fields = Build.class.getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                mInfos.put(field.getName(), field.get(null).toString());
            } catch (Exception e) {
                log.error("An error occured when collect crash info, Error: " + e);
            }
        }
    }

    /**
     * 5.3 保存log和crash到文件
     * 
     * @param ex
     */
    protected void saveLogAndCrash(Throwable ex) {
        log.info("DRCrashHandler is saving Log! ");

        StringBuffer sb = new StringBuffer();

        sb.append("[DateTime: " + DateUtil.date2String(new Date()) + "]
");
        sb.append("[DeviceInfo: ]
");
        // 遍历infos
        for (Map.Entry<String, String> entry : mInfos.entrySet()) {
            String key = entry.getKey().toLowerCase(Locale.getDefault());
            String value = entry.getValue();
            sb.append("  " + key + ": " + value + "
");
        }
        // 将错误手机到writer中
        Writer writer = new StringWriter();
        PrintWriter pw = new PrintWriter(writer);
        ex.printStackTrace(pw);
        Throwable cause = ex.getCause();
        while (cause != null) {
            cause.printStackTrace(pw);
            cause = cause.getCause();
        }
        pw.close();
        String result = writer.toString();
        sb.append("[Excetpion: ]
");
        sb.append(result);

        // 将异常写入日志文件
        log.error(result);

        // 5.3.1 记录异常到特定文件中
        saveToCrashFile(sb.toString());

    }

    /**
     * 5.3.1写入文本
     * 
     * @param crashText
     */
    protected void saveToCrashFile(String crashText) {
        log.info("DRCrashHandler is writing crash-info to CrashFile(" + this.mDRCrashFilePath + ")! ");

        crashFile = new File(mDRCrashFilePath);

        // 创建文件(自己写的操作文件相关的工具类)
        FileUtil.createFileAndFolder(crashFile);

        // 追加文本(自己写的操作文件相关的工具类)
        FileUtil.appendToFile(crashFile, crashText);

    }

    /**
     * 5.4 发送log和crash到服务器
     */
    protected void sendLogAndCrash() {
        logFile = new File(mContext.getDrLogHelper().getLog4jFilePath());
        crashFile = new File(getDRCrashFilePath());
        // 5.4.1
        sendToServer(logFile, crashFile);
    }

    /**
     * 5.4.1 将错误报告发送到服务器
     * 
     * @param crashFile
     * @param logFile
     */
    protected abstract void sendToServer(File logFile, File crashFile);

    public String getDRTipMsg() {
        return mDRTipMsg;
    }

    /**
     * 设置程序崩溃提示信息
     * 
     * @param mDRTipMsg
     */
    public void setDRTipMsg(String mDRTipMsg) {
        this.mDRTipMsg = mDRTipMsg;
    }

    public String getDRCrashFilePath() {
        return mDRCrashFilePath;
    }

    /**
     * 设置记录崩溃信息的文件位置
     * 
     * @param mDRCrashFilePath
     */
    public void setDRCrashFilePath(String mDRCrashFilePath) {
        this.mDRCrashFilePath = mDRCrashFilePath;
    }

}

2、新建DRApplication.java(抽象类,里面用到了Log4j,上一篇有讲到如果在Android中集成Log4j,这里在Application中使用DRLogHelper来初始化log4j)

package cn.dr.lib.app;

import java.io.File;
import java.util.LinkedList;
import java.util.List;

import org.apache.log4j.Logger;

import android.app.Activity;
import android.app.Application;
import cn.dr.lib.log.DRLogHelper;
import cn.dr.lib.ui.DRAcitivity;

/**
 * DarkRanger的Application
 * 
 * @author DarkRanger
 *
 */
public abstract class DRApplication extends Application {

    // 当前类的log
    private static Logger log;

    // Activity列表
    private List<DRAcitivity> mActivityList = new LinkedList<DRAcitivity>();

    // drLog实例
    public DRLogHelper mDRLogHelper = DRLogHelper.getInstance();

    // 全局异常处理类的实例
    public DRCrashHandler mDRCrashHandler = new DRCrashHandler() {

        @Override
        public void initParams() {

        }

        @Override
        public void sendToServer(File logFile, File crashFile) {

        }

    };

    @Override
    public void onCreate() {

        super.onCreate();

        // 1、初始化DRLog参数
        initDRLogHelperParam();

        // 2、初始化DRLog
        initDRLogHelper();

        // 3、初始化全局异常处理类
        initCrashHandler();
    }

    /**
     * 1、初始化DRLog参数,如: <br/>
     * 
     * {@link DRApplication#getDrlog()} DRLog drLog = getDrlog(); <br/>
     * {@link DRLogHelper#setLog4jFilePath(String)}
     * drLog.setLog4jFilePath(Constants.LOG4J_FILE_PATH); <br/>
     * {@link DRLogHelper#setType(cn.dr.lib.log.DRLogHelper.LogType)}
     * drLog.setType(LogType.TYPE_LOG4J); <br/>
     * 
     * 只有在子类中完成initDRLogParam参数设置以后才能使用log
     */
    protected abstract void initDRLogHelperParam();

    /**
     * 2、初始化DRLog
     */
    private void initDRLogHelper() {
        getDrLogHelper().init();

        log = Logger.getLogger(DRApplication.class);
    }

    /**
     * 3、初始化CrashHandler
     */
    private void initCrashHandler() {
        log.trace("DRApplication: initCrashHandler()");

        // 3.1
        setHandler();

        // 3.2
        getDRCrashHandler().init(this);
    }

    /**
     * 
     * 3.1 调用以下方法为mCrashHandler设置实例<br/>
     * <br/>
     * 
     * {@link #setCrashHandler(DRCrashHandler)}
     */
    public abstract void setHandler();

    /**
     * 获取DRLog单例
     * 
     * @return
     */
    public DRLogHelper getDrLogHelper() {
        return mDRLogHelper;
    }

    public DRCrashHandler getDRCrashHandler() {
        return mDRCrashHandler;
    }

    public void setDRCrashHandler(DRCrashHandler mCrashHandler) {
        this.mDRCrashHandler = mCrashHandler;
    }

    /**
     * 添加activity到App的mActivityList
     * 
     * @param activity
     */
    public void addActivity(DRAcitivity activity) {
        this.mActivityList.add(activity);
    }

    /**
     * 遍历mActivityList,结束每一个activity的声明周期
     */
    private void finishActivityList() {
        for (Activity activity : mActivityList) {
            activity.finish();
        }
    }

    @Override
    public void onTerminate() {
        log.trace("DRApplication: onTerminate()");

        super.onTerminate();
        appExit();
    }

    /**
     * 完全退出程序
     */
    public void appExit() {
        log.trace("DRApplication: appExit()");

        finishActivityList();
        // 正常退出
        System.exit(0);
    }

    /**
     * 出现异常杀掉进程
     */
    public void appKill() {
        log.trace("DRApplication: appKill()");

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

}

 3、

首先要说明的是:前面两个类我已经集成在DR_supprot_lib库中,在新的应用程序中只需要继承这两个类,分类初始化一些参数即可。

写个App程序测试:

3.1 新建MyCrashHandler.java继承DRCrashHandler,复写两个抽象方法initParams()和sendToServer()

package cn.darkranger.test;

import java.io.File;

import org.apache.log4j.Logger;

import android.os.Environment;
import cn.dr.lib.app.DRCrashHandler;

public class MyCrashHandler extends DRCrashHandler {
    private static final Logger log = Logger.getLogger(MyCrashHandler.class);

    String crashFilePath = Environment.getExternalStorageDirectory() + File.separator + "MyApp" + File.separator
            + "Crash.txt";

    @Override
    public void initParams() {
        // 设置程序崩溃提示信息
        setDRTipMsg("this is my msg - -");
        // 设置程序崩溃的文件位置
        setDRCrashFilePath(crashFilePath);
    }

    @Override
    protected void sendToServer(File logFile, File crashFile) {
        log.info("logFile: " + logFile + "; crashFile: " + "
action:sendToServer - -");
        // 这里要写上传错误信息到服务器的代码,暂时不写,看需求,自己实现
    }

}

3.2 新建MyApplication.java继承DRApplication,复写两个抽象方法initDRLogHelperParam()和setHandler()

package cn.darkranger.test;

import java.io.File;

import org.apache.log4j.Logger;

import android.os.Environment;
import cn.dr.lib.app.DRCrashHandler;

public class MyCrashHandler extends DRCrashHandler {
    private static final Logger log = Logger.getLogger(MyCrashHandler.class);

    String crashFilePath = Environment.getExternalStorageDirectory() + File.separator + "MyApp" + File.separator
            + "Crash.txt";

    @Override
    public void initParams() {
        // 设置程序崩溃提示信息
        setDRTipMsg("this is my msg - -");
        // 设置程序崩溃的文件位置
        setDRCrashFilePath(crashFilePath);
    }

    @Override
    protected void sendToServer(File logFile, File crashFile) {
        log.info("logFile: " + logFile + "; crashFile: " + "
action:sendToServer - -");
        // 这里要写上传错误信息到服务器的代码,暂时不写,看需求,自己实现
    }

}

3.3 新建MainActivity,这里暂时不继承DRActivity,继承AppCompatActivity,两个testview,点击第一个,调用DRApplication的退出,点击第二个,抛出异常,我们自己捕获。

package cn.darkranger.test;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView exitTv = (TextView) findViewById(R.id.id_exit);
        exitTv.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                ((MyApplication) getApplication()).appExit();
            }
        });

        TextView testCrashTv = (TextView) findViewById(R.id.id_testCrash);
        testCrashTv.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                throw new IllegalArgumentException("this is an IllegalArgumentException! ");
            }
        });

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

 3.4 更改AndroidManifest.xml(添加读写文件的权限,设置application为:cn.darkranger.test.MyApplication)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="cn.darkranger.test"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="11"
        android:targetSdkVersion="21" />

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

    <application
        android:name="cn.darkranger.test.MyApplication"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

测试:

运行,点击第一个按钮,退出程序,查看log文件:

[2016-06-30 22:19:09][Class: cn.dr.lib.log.DRLogHelper.initLog4j(DRLogHelper.java:89)] 
[Level: INFO ] - Msg: Log4j is Ready For DRApplication! 

[2016-06-30 22:19:09][Class: cn.dr.lib.app.DRApplication.initCrashHandler(DRApplication.java:87)] 
[Level: TRACE] - Msg: DRApplication: initCrashHandler()

[2016-06-30 22:19:09][Class: cn.dr.lib.app.DRCrashHandler.init(DRCrashHandler.java:65)] 
[Level: INFO ] - Msg: DRCrashHandler is Ready For Application! 

[2016-06-30 22:19:12][Class: cn.dr.lib.app.DRApplication.appExit(DRApplication.java:152)] 
[Level: TRACE] - Msg: DRApplication: appExit()

[2016-06-30 22:19:58][Class: cn.dr.lib.log.DRLogHelper.initLog4j(DRLogHelper.java:89)] 
[Level: INFO ] - Msg: Log4j is Ready For DRApplication! 

[2016-06-30 22:19:58][Class: cn.dr.lib.app.DRApplication.initCrashHandler(DRApplication.java:87)] 
[Level: TRACE] - Msg: DRApplication: initCrashHandler()

[2016-06-30 22:19:58][Class: cn.dr.lib.app.DRCrashHandler.init(DRCrashHandler.java:65)] 
[Level: INFO ] - Msg: DRCrashHandler is Ready For Application! 

[2016-06-30 22:20:02][Class: cn.dr.lib.app.DRApplication.appExit(DRApplication.java:152)] 
[Level: TRACE] - Msg: DRApplication: appExit()

运行,点击第二个按钮,抛出异常,查看log文件和crash文件:

Log.txt

[2016-06-30 22:19:09][Class: cn.dr.lib.log.DRLogHelper.initLog4j(DRLogHelper.java:89)] 
[Level: INFO ] - Msg: Log4j is Ready For DRApplication! 

[2016-06-30 22:19:09][Class: cn.dr.lib.app.DRApplication.initCrashHandler(DRApplication.java:87)] 
[Level: TRACE] - Msg: DRApplication: initCrashHandler()

[2016-06-30 22:19:09][Class: cn.dr.lib.app.DRCrashHandler.init(DRCrashHandler.java:65)] 
[Level: INFO ] - Msg: DRCrashHandler is Ready For Application! 

[2016-06-30 22:19:12][Class: cn.dr.lib.app.DRApplication.appExit(DRApplication.java:152)] 
[Level: TRACE] - Msg: DRApplication: appExit()

[2016-06-30 22:19:58][Class: cn.dr.lib.log.DRLogHelper.initLog4j(DRLogHelper.java:89)] 
[Level: INFO ] - Msg: Log4j is Ready For DRApplication! 

[2016-06-30 22:19:58][Class: cn.dr.lib.app.DRApplication.initCrashHandler(DRApplication.java:87)] 
[Level: TRACE] - Msg: DRApplication: initCrashHandler()

[2016-06-30 22:19:58][Class: cn.dr.lib.app.DRCrashHandler.init(DRCrashHandler.java:65)] 
[Level: INFO ] - Msg: DRCrashHandler is Ready For Application! 

[2016-06-30 22:20:02][Class: cn.dr.lib.app.DRApplication.appExit(DRApplication.java:152)] 
[Level: TRACE] - Msg: DRApplication: appExit()

[2016-06-30 22:20:48][Class: cn.dr.lib.log.DRLogHelper.initLog4j(DRLogHelper.java:89)] 
[Level: INFO ] - Msg: Log4j is Ready For DRApplication! 

[2016-06-30 22:20:48][Class: cn.dr.lib.app.DRApplication.initCrashHandler(DRApplication.java:87)] 
[Level: TRACE] - Msg: DRApplication: initCrashHandler()

[2016-06-30 22:20:48][Class: cn.dr.lib.app.DRCrashHandler.init(DRCrashHandler.java:65)] 
[Level: INFO ] - Msg: DRCrashHandler is Ready For Application! 

[2016-06-30 22:20:50][Class: cn.dr.lib.app.DRCrashHandler.uncaughtException(DRCrashHandler.java:109)] 
[Level: INFO ] - Msg: DRCrashHandler dispatcher uncaughtException! 

[2016-06-30 22:20:50][Class: cn.dr.lib.app.DRCrashHandler.handlerException(DRCrashHandler.java:139)] 
[Level: INFO ] - Msg: DRCrashHandler is handling Exception! 

[2016-06-30 22:20:50][Class: cn.dr.lib.app.DRCrashHandler.collectDeviceInfo(DRCrashHandler.java:175)] 
[Level: INFO ] - Msg: DRCrashHandler is collecting DeviceInfo! 

[2016-06-30 22:20:50][Class: cn.dr.lib.app.DRCrashHandler.saveLogAndCrash(DRCrashHandler.java:206)] 
[Level: INFO ] - Msg: DRCrashHandler is saving Log! 

[2016-06-30 22:20:50][Class: cn.dr.lib.app.DRCrashHandler.run(DRCrashHandler.java:151)] 
[Level: INFO ] - Msg: DRCrashHandler is ready send crash-info to device!

[2016-06-30 22:20:50][Class: cn.dr.lib.app.DRCrashHandler.saveLogAndCrash(DRCrashHandler.java:233)] 
[Level: ERROR] - Msg: java.lang.IllegalArgumentException: this is an IllegalArgumentException! 
    at cn.darkranger.test.MainActivity$2.onClick(MainActivity.java:33)
    at android.view.View.performClick(View.java:4792)
    at android.view.View$PerformClick.run(View.java:19936)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5595)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:964)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:759)


[2016-06-30 22:20:50][Class: cn.dr.lib.app.DRCrashHandler.saveToCrashFile(DRCrashHandler.java:246)] 
[Level: INFO ] - Msg: DRCrashHandler is writing crash-info to CrashFile(/storage/emulated/0/MyApp/Crash.txt)! 

[2016-06-30 22:20:50][Class: cn.dr.lib.utils.FileUtil.createFileAndFolder(FileUtil.java:444)] 
[Level: INFO ] - Msg: File[/storage/emulated/0/MyApp/Crash.txt] was created successfully! 

[2016-06-30 22:20:50][Class: cn.darkranger.test.MyCrashHandler.sendToServer(MyCrashHandler.java:26)] 
[Level: INFO ] - Msg: logFile: /storage/emulated/0/MyApp/Log.txt; crashFile: 
action:sendToServer - -

[2016-06-30 22:20:53][Class: cn.dr.lib.app.DRApplication.appExit(DRApplication.java:152)] 
[Level: TRACE] - Msg: DRApplication: appExit()

Crash.txt

[DateTime: 2016-06-30 22:20:50]
[DeviceInfo: ]
  supported_64_bit_abis: [Ljava.lang.String;@16d078ef
  versioncode: 1
  board: mozart
  bootloader: unknown
  type: user
  matchers: [Ljava.lang.String;@3d5b7685
  id: HUAWEIM2-801W
  time: 1437332391000
  brand: HUAWEI
  tag: Build
  serial: TJF4C15804003585
  hardware: hi3635
  supported_abis: [Ljava.lang.String;@33767ffc
  no_hota: false
  cpu_abi: arm64-v8a
  radio: unknown
  is_debuggable: false
  replacements: [Ljava.lang.String;@2dec2cda
  manufacturer: HUAWEI
  supported_32_bit_abis: [Ljava.lang.String;@3271c1ce
  tags: ota-rel-keys,release-keys
  cpu_abi2: 
  unknown: unknown
  user: huawei
  fingerprint: HUAWEI/M2/HWMozart:5.1.1/HUAWEIM2-801W/C233B009:user/release-keys
  host: WUH1000005635
  product: M2
  versionname: 1.0
  display: M2-801WV100R001C233B009
  hide_product_info: false
  model: HUAWEI M2-801W
  device: HWMozart
[Excetpion: ]
java.lang.IllegalArgumentException: this is an IllegalArgumentException! 
    at cn.darkranger.test.MainActivity$2.onClick(MainActivity.java:33)
    at android.view.View.performClick(View.java:4792)
    at android.view.View$PerformClick.run(View.java:19936)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5595)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:964)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:759)
原文地址:https://www.cnblogs.com/wrcold520/p/5631479.html