当程序遇到Crash的时候

转载请注明[图你怀中安稳] http://blog.csdn.net/qq_32648731/article/details/77571535
在开发中我们最不想看见的应该是Crash了,当我们的程序上线,投放到市场的时候,用户会去使用我们的软件,这时,我们更加不希望我们的应用程序会Crash,当然在开发中,我们要是遇见可控的Crash,我们会立马解决,但是Android程序不知道为什么?有的Crash是不能被测试出来的,这时我们当然不能修改了,只有当它发生Crash的时候才能知道哪里出现了问题,但是这时我们不会等待这个Crash的出现,我们会将程序上线,这时,我们就需要知道在用户面前发生的Crash是什么,以便于我们在下一版本中进行修改,


我们因该想到的是,当发生Crash的时候,将这个Crash的信息记录到本地,然后在联网的时候找个最佳时段发送给我们的后台,我们进行分析,找到Crash的原因,那么怎么上报呢?Android给我们提供了这个方法,那就是Thread 类中的这个方法

 public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
         defaultUncaughtExceptionHandler = eh;
     }

从翻译来看,这个方法叫设置默认的捕获的异常处理程序,当然,这个方法就是能在程序Crash时商报异常信息的方法,
那这个使用步骤是什么呢?

1、建立异常处理的Handler

我就直接上代码了

/**
 * Created by mr.kong on 2017/8/25.
 * 使用单列模式
 */
class CrashHandler private constructor(mContext: Context) : Thread.UncaughtExceptionHandler {

    private var context: Context? = null
    //系统默认的异常处理
    private var mDefaultCrashHandler: Thread.UncaughtExceptionHandler? = null

    companion object {
        val DEBUG = true
        val TAG = CrashHandler::class.simpleName
        val PATH = Environment.getExternalStorageDirectory().path + "/kpa/log" //路径
        val LOG_NAME = "crash" //名字
        val FILE_NAME_SUFFIX = ".trace" //后缀名
        @Volatile
        var instance: CrashHandler? = null

        fun getInstance(mContext: Context): CrashHandler {
            if (instance == null) {
                synchronized(CrashHandler::class) {
                    if (instance == null) {
                        instance = CrashHandler(mContext)
                    }
                }
            }
            return instance!!
        }

    }

    /**
     * 初始化
     */
    fun init(mContext: Context) {
        //获取系统默认的异常处理
        mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler()
        //将当前实例设为系统默认的异常处理器
        Thread.setDefaultUncaughtExceptionHandler(this)
        //获取Context,方便内部使用
        context = mContext?.applicationContext
    }


    /**
     * 当程序Crash的时候,未捕获的异常,系统会自动调用uncaughtException这个方法,
     * @param t 捕获这个异常的线程
     * @param e 这个异常的信息
     */
    override fun uncaughtException(t: Thread?, e: Throwable?) {
        try {
            //把异常信息写到SD卡中
            saveCrashInfo(e)
            //找时间将信息上报服务器
            reportCrashInfoToServer()
        } catch (e: Exception) {

        }

        //如果系统提供了默认的异常处理器,则交给系统去结束我们的程序,否则就由我们自己结束自己
        if (mDefaultCrashHandler != null) {
            mDefaultCrashHandler?.uncaughtException(t, e)
        } else {
            Process.killProcess(Process.myPid())
        }
    }

    /**
     * 上报异常信息到服务器
     */
    private fun reportCrashInfoToServer() {
        //上报逻辑
    }

    @Throws(IOException::class)
    private fun saveCrashInfo(e: Throwable?) {
        //如果SD不存在,或者无法使用,则不能将信息保存起来
        if (Environment.getExternalStorageState() != Environment.MEDIA_MOUNTED) {
            if (DEBUG) {
                Log.w(TAG, "SD 卡不能用")
                return
            }
        }

        val dir = File(PATH)
        if (!dir.exists()) {
            dir.mkdirs()
        }

        //获取当前时间
        val currentTimeMillis = System.currentTimeMillis()
        val time = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(currentTimeMillis)
        //以当前时间创建Log文件
        val file = File(PATH + LOG_NAME + time + FILE_NAME_SUFFIX)

        val printWriter = PrintWriter(file)
        printWriter.println(time)//导出异常发生的时间
        //要到处手机信息,知道具体是什么机型发生的Crash
        exportPhoneInfo(printWriter)
        printWriter.println()
        //导出异常信息
        e?.printStackTrace(printWriter)
        printWriter.close()

    }


    @Throws(NameNotFoundException::class)
    private fun exportPhoneInfo(printWriter: PrintWriter) {
        //获取应用名称和版本号
        val packageManager = context?.packageManager
        val packageInfo = packageManager?.getPackageInfo(context?.packageName, PackageManager.GET_ACTIVITIES)
        printWriter.print("APP VERSION:")
        printWriter.print(packageInfo?.versionName)
        printWriter.print("--")
        printWriter.print(packageInfo?.versionCode)

        //android 的版本号
        printWriter.print("ANDROID VERSION")
        printWriter.print(Build.VERSION.RELEASE)
        printWriter.print("--")
        printWriter.print(Build.VERSION.SDK_INT)

        //手机制造商
        printWriter.print("PHONE MODEL")
        printWriter.print(Build.MODEL)

        //cpu框架
        printWriter.print("CPU ABI")
        printWriter.print(Build.CPU_ABI)


    }

}

2、我们已经定义了收集异常信息的Handler 解析来我们在UI线程中添加默认处理异常信息的处理,我们将它添加到Application 中

package com.tcm.crash

import android.app.Application
import com.tcm.crash.crash.CrashHandler

/**
 * Created by mr.kong on 2017/8/25.
 */
class MyApp : Application() {

    override fun onCreate() {
        super.onCreate()

        val instance = CrashHandler.getInstance(this)
        instance.init(this)
    }
}

到此为止我们的程序在不知情况下Crash的情况就解决了

发布了53 篇原创文章 · 获赞 20 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_32648731/article/details/77571535