這可能是最好的 Android/Kotlin日誌輸出方法
- 2020 年 1 月 23 日
- 筆記
在編程調試和定位問題的時候,日誌是一個最常用的工具。比如輸出一些資訊,確定執行軌跡。今天我們這裡簡單聊一聊列印日誌的一些分析。
通常,我們進行日誌輸出的時候都會限定在debug包下執行,對於非debug包,我們就不輸出日誌。那麼如果是非debug,不同的日誌輸出方式可能存在一定的性能問題,本文將通過幾個版本來對比著方面的差異。
原始版
這可能是最原始的版本列印日誌了,判斷是否是debug,然後決定是否輸出日誌
|
1 2 3 4 5 6 7 8 9 |
fun debugLog(message: String?) { if (BuildConfig.DEBUG) { Log.d("debugLog", message) } } private fun testDebugLog() { debugLog("getProperties " + getProperties()?.joinToString()) } |
|---|
上面的問題
testDebugLog需要執行getProperties(),這一步的性能不可預知testDebugLog內部存在字元串拼接- 如果拼接內容複雜,比如一個龐大的Object,會造成一定的開銷
- 綜上所述,該實現如果在
非Debug條件下存在一定的運行時開銷
不拼接的版本
既然拼接會導致一些問題,那麼下面的版本採用(調用處)不拼接的形式
|
1 2 3 4 5 6 7 8 9 |
fun debugMessage(vararg args: Any?) { if (BuildConfig.DEBUG) { Log.d("debugMessage", args.joinToString()) } } private fun testDebugMessage() { debugMessage("getProperties", getProperties()) } |
|---|
- 仍然需要執行
getProperties(),這一步的性能不可預知 - 上面的程式碼使用了可變參數的形式處理message資訊
- 而可變參數內部實際採用了數組的形式,也就是上面的程式碼會在運行時生成一個數組,一個元素是
getProperties,另一個元素是getProperties()的內容 - 這個版本相對第一個版本要好一些(以極端情況看),但是
在非Debug條件下仍然存在一定的運行時開銷,不完美。
相對最完美的版本
這個版本是相對最好的實現,規避了非Debug環境下的字元串拼接和具體求值的操作
|
1 2 3 4 5 6 7 8 9 10 11 |
inline fun smartMessage(lazyMessage: () -> Any?) { if (BuildConfig.DEBUG) { Log.d("smartMessage", lazyMessage().toString()) } } private fun testSmartMessage() { smartMessage { "getProperties " + getProperties() } } |
|---|
- 上面使用了Lambda表達式來生成message資訊
如何巧妙地規避不必要的開銷
當我們反編譯Kotlin 程式碼 到 Java程式碼時,一切就清晰了。
|
1 2 3 4 5 6 7 8 9 10 |
private final void testSmartMessage() { int $i$f$smartMessage = false; if (BuildConfig.DEBUG) { String var3 = "smartMessage"; int var2 = false; String var4 = "getProperties " + this.getProperties(); Log.d(var3, String.valueOf(var4)); } } |
|---|
- 之前的Lambda 由於採用了 inline 處理 會把
smartMessage提取到調用處testSmartMessage - 上面的資訊,都是確保了在
BuildConfig.DEBUG成立時才執行,否則不執行 - 上面的做法,利用了Kotlin的特性,就運行時可能存在的開銷一下就移除了。
注意
- smartMessage 建議只在 Kotlin 中調用,否則會生成實例,因為無法inline處理

