转载请注明[图你怀中安稳] 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的情况就解决了