Android自带的日志类不支持显示文件名和行号,调试时很不方便。而第三方日志库往往又太重。所以自己对Android自带的日志类做了一个简单的封装,主要是调试时使用,不考虑日志丢失和性能问题。日志的输出如下:
08-12 13:26:25.557 31285 31285 D com.tq.test: [TestFragment.kt:85 com.tq.test.fragment.TestFragment$subscribeUi$5.onChanged] foo bar
用法如下:
// 在Activity或Fragment中
val someValue = "abc";
getLogger().debug(someValue)
getLogger().debug(someValue, x, y, z)
getLogger().error(ex)
// CrashHandler
package com.tq.test
import android.os.Process
import com.tq.test.utility.Logger
class DefaultExceptionHandler(
private val packageName: String,
private val next: Thread.UncaughtExceptionHandler? = null
): Thread.UncaughtExceptionHandler {
override fun uncaughtException(thread: Thread, error: Throwable) {
val logger = Logger.getLogger(packageName)
logger.error(error, "uncaught exception", thread)
next?.uncaughtException(thread, error)
Process.killProcess(Process.myPid())
}
}
Thread.setDefaultUncaughtExceptionHandler(DefaultExceptionHandler(
getPackageName(),
Thread.getDefaultUncaughtExceptionHandler()
))
源代码如下:
package com.tq.utility
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import android.content.Context
import android.util.Log
class Logger private constructor(val defaultTag: String = "") {
fun debug(vararg values: Any?) = Log.d(defaultTag, makeMessage(values))
fun info(vararg values: Any?) = Log.i(defaultTag, makeMessage(values))
fun warn(vararg values: Any?) = Log.w(defaultTag, makeMessage(values))
fun error(error: Throwable, vararg values: Any?) = Log.e(defaultTag, makeMessage(values), error)
private fun makeMessage(values: Array): String {
// TOOD handle native method
var fileName = "unknown"
var lineNumber = -1
var className = "unknown"
var methodName ="unknown"
val throwable = Throwable()
val stacks = throwable.getStackTrace()
val depth = 2
if (stacks.size > depth) {
val stack = stacks[depth]
fileName = stack.getFileName()
lineNumber = stack.getLineNumber()
className = stack.getClassName()
methodName = stack.getMethodName()
}
val valueString = values.map{ it?.toString() ?: "null" }.joinToString()
return "[$fileName:$lineNumber $className.$methodName] $valueString"
}
companion object {
fun getLogger(tag: String): Logger {
return Logger(tag)
}
fun getLogger(context: Context) = getLogger(context.getPackageName())
}
}
fun AppCompatActivity.getLogger() = Logger.Companion.getLogger(this)
fun Fragment.getLogger() = Logger.Companion.getLogger(activity!!)