Android自定义全局异常捕获类统一处理App异常

基本思路

统一应用所有崩溃异常入口,当应用崩溃的时候记录相关崩溃日志到本地并在合适时间上传至服务器;

相关实现

package com.crystal.view.exception

import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.os.Environment
import android.util.Log
import java.io.File
import java.io.FileOutputStream
import java.io.PrintWriter
import java.io.StringWriter

/**
 * 自定义全局异常捕获类
 * on 2022/11/17
 */
class ExceptionCrashHandler private constructor() : Thread.UncaughtExceptionHandler {
    private lateinit var context: Context

    private lateinit var defaultExceptionCrashHandler: Thread.UncaughtExceptionHandler

    /**
     * 双重DCL单例
     */
    companion object {
        val TAG = ExceptionCrashHandler::class.java.simpleName
        val instance: ExceptionCrashHandler by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            ExceptionCrashHandler()
        }
    }

    /**
     * 初始化
     */
    fun init(context: Context) {
        this.context = context
        //设置全局的异常类为本类
        Thread.currentThread().uncaughtExceptionHandler = this
        //获取系统默认的异常处理
        defaultExceptionCrashHandler =
            Thread.getDefaultUncaughtExceptionHandler() as Thread.UncaughtExceptionHandler;
    }

    override fun uncaughtException(t: Thread, e: Throwable) {
        Log.e(TAG, "此处有异常!!!")

        //这里我们可以将崩溃信息保存到本地文件,找机会上传至服务器,如再次打开APP时遍历查找crash文件上传
        saveExceptionInfoToLocal(e)


        //让系统默认处理,不加会默认不抛异常
        defaultExceptionCrashHandler.uncaughtException(t, e)
    }


    /**
     * 记录错误信息到本地
     */
    private fun saveExceptionInfoToLocal(e: Throwable) {
        //获取相关信息
        val appInfo = getAppInfo(e)
        if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) {
            val crashFile = File(context.filesDir.path + File.separator + "crash" + File.separator)
            val fileName = crashFile.path +  System.currentTimeMillis().toString() + ".txt"
            val fos = FileOutputStream(fileName)
            fos.write(appInfo.toByteArray())
            fos.flush()
            fos.close()
        }

    }

    /**
     * 获取手机相关信息(可以拼接想要记录的异常信息)
     */
    private fun getAppInfo(e: Throwable): String {
        val packageManager = context.packageManager
        val packageInfo =
            packageManager.getPackageInfo(context.packageName, PackageManager.GET_ACTIVITIES)
        val stringBuffer = StringBuffer()
        stringBuffer.append("VersionName:" + packageInfo.versionName)
        stringBuffer.append("\n")
        stringBuffer.append("VersionCode:" + packageInfo.versionCode)
        stringBuffer.append("\n")

        //反射获取Build类中的相关属性信息
        val buildClazz = Build::class.java
        val deviceField = buildClazz.getDeclaredField("DEVICE")
        val device = deviceField.get(null)
        stringBuffer.append("device:$device")
        stringBuffer.append("\n")
        val productField = buildClazz.getDeclaredField("PRODUCT")
        val product = productField.get(null)
        stringBuffer.append("product:$product")
        stringBuffer.append("\n")

        //记录异常信息
        val stringWriter = StringWriter()
        val printWriter = PrintWriter(stringWriter)
        e.printStackTrace(printWriter)
        printWriter.close()
        stringBuffer.append(stringWriter.toString())
        return stringBuffer.toString()
    }
}

验证

class BaseApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        ExceptionCrashHandler.instance.init(this)
    }
}

class MainActivity : AppCompatActivity() {
    @BindView(R.id.tv)
    private var tv: TextView? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        InjectUtils.bind(this)
    }

    @OnClick(R.id.tv, R.id.tv)
    private fun onClick(view: View) {
        //故意引入崩溃
        Toast.makeText(this, "Send Message for you" + 2 / 0, Toast.LENGTH_LONG).show()
    }

}

本地记录崩溃信息

崩溃信息

结语

如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值