对于 Android 开发,当我们需要在类中打印 Log 时,通常在Java中会这么定义一个 TAG:
private static final String TAG = "TestClass";
或者不具体指定名字:
private static final String TAG = TestClass.class.getSimpleName();
那么,在 Kotlin 中
我们通常会这样定义:
private val TAG = TestClass::class.java.simpleName
或者采用类似于 Java 的静态方式实现:
companion object {
private val TAG = TestClass::class.java.simpleName
}
甚至还加上 @JvmField 注解,方便外部调用:
companion object {
@JvmField val TAG: String = TestClass::class.java.simpleName
}
companion object 的属性/方法会产生额外的 static final 的同伴类实例,因此在性能和内存方面都很糟糕,所以大可不必将 TAG 放在 companion object,下面2张图或许可以告诉你一些东西:
以上方式,都需要在每个类定义相应的 TAG,是比较繁琐的。
那么,在 Kotlin 中可以通过扩展函数统一声明 TAG,避免在每个类中定义相应的 TAG。
我们可以通过如下两种方式实现:
方式一:
val Any.TAG: String
get() {
return javaClass.simpleName
}
方式二:
inline val T.TAG: String
get() = T::class.java.simpleName
我们知道,从API 24开始,TAG 就没有长度限制,所以需要对长度做个兼容:
方式一:
val Any.TAG: String
get() {
val name = javaClass.simpleName
return if (name.length <= 23 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) name
else name.substring(0, 23)
}
方式二:
inline val T.TAG: String
get() {
val name = T::class.javaClass.simpleName
return if (name.length <= 23 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) name
else name.substring(0, 23)
}
匿名内部类长度较长,我们可以使用 name 代替 simpleName 去解析相应 TAG:
方式一:
val Any.TAG: String
get() {
return if (!javaClass.isAnonymousClass) {
val name = javaClass.simpleName
if (name.length <= 23 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) name
else name.substring(0, 23)
} else {
val name = javaClass.name
if (name.length <= 23 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) name
else name.substring(name.length - 23, name.length)
}
}
方式二:
inline val T.TAG: String
get() {
return if (!T::class.javaClass.isAnonymousClass) {
val name = T::class.javaClass.simpleName
if (name.length <= 23 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) name
else name.substring(0, 23)
} else {
val name = T::class.javaClass.name
if (name.length <= 23 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) name
else name.substring(name.length - 23, name.length)
}
}
当类被混淆时,simpleName 不是一个好的解决方案,例如 MyActivity 可能会变成 M,此刻或许在类中显示声明 TAG 会更好:
private val TAG = "TestClass"
两种方式差别不大,由于作者更喜欢方式二内联实现,所以本文推荐方式二,实现一劳永逸的 TAG。
inline val T.TAG: String
get() {
return if (!T::class.javaClass.isAnonymousClass) {
val name = T::class.javaClass.simpleName
if (name.length <= 23 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) name
else name.substring(0, 23)
} else {
val name = T::class.javaClass.name
if (name.length <= 23 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) name
else name.substring(name.length - 23, name.length)
}
}
【Extensions.kt 文件】
package com.agg.utils
import android.os.Build
/**
* Description:
* CreateDate: 2023/6/20 16:12
* Author: agg
*/
class Extensions {}
// private static final String TAG = "TestClass";
// private static final String TAG = TestClass.class.getSimpleName();
// private val TAG = TestClass::class.java.simpleName
// companion object {
// private val TAG = TestClass::class.java.simpleName
// }
// companion object {
// @JvmField val TAG: String = TestClass::class.java.simpleName
// }
//val Any.TAG: String
// get() {
// return javaClass.simpleName
// }
//inline val T.TAG: String
// get() = T::class.java.simpleName
//val Any.TAG: String
// get() {
// val name = javaClass.simpleName
// return if (name.length <= 23 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) name
// else name.substring(0, 23)
// }
//inline val T.TAG: String
// get() {
// val name = T::class.javaClass.simpleName
// return if (name.length <= 23 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) name
// else name.substring(0, 23)
// }
//val Any.TAG: String
// get() {
// return if (!javaClass.isAnonymousClass) {
// val name = javaClass.simpleName
// if (name.length <= 23 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) name
// else name.substring(0, 23)
// } else {
// val name = javaClass.name
// if (name.length <= 23 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) name
// else name.substring(name.length - 23, name.length)
// }
// }
inline val T.TAG: String
get() {
return if (!T::class.javaClass.isAnonymousClass) {
val name = T::class.javaClass.simpleName
if (name.length <= 23 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) name
else name.substring(0, 23)
} else {
val name = T::class.javaClass.name
if (name.length <= 23 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) name
else name.substring(name.length - 23, name.length)
}
}
【参考文档】在Kotlin中定义log TAG常量的最佳方式是什么?