Kotlin 一劳永逸实现 TAG

1 TAG 经典写法

        对于 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张图或许可以告诉你一些东西:

Kotlin 一劳永逸实现 TAG_第1张图片

Kotlin 一劳永逸实现 TAG_第2张图片

2 TAG 一劳永逸

        以上方式,都需要在每个类定义相应的 TAG,是比较繁琐的。

        那么,在 Kotlin 中可以通过扩展函数统一声明 TAG,避免在每个类中定义相应的 TAG。

我们可以通过如下两种方式实现:

        方式一:

val Any.TAG: String
    get() {
        return javaClass.simpleName
    }

        方式二:

inline val  T.TAG: String
    get() = T::class.java.simpleName

3 TAG 持续优化

3.1 TAG 长度限制

        我们知道,从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)
    }

3.2 匿名内部类的 TAG

        匿名内部类长度较长,我们可以使用 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)
        }
    }

3.3 类被混淆的 TAG

        当类被混淆时,simpleName 不是一个好的解决方案,例如 MyActivity 可能会变成 M,此刻或许在类中显示声明 TAG 会更好:

    private val TAG = "TestClass"

4 推荐写法

        两种方式差别不大,由于作者更喜欢方式二内联实现,所以本文推荐方式二,实现一劳永逸的 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)
        }
    }


走一段令人留恋的路,做一个不负自己的人

本文 Demo 代码参考参见后文


【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常量的最佳方式是什么?

你可能感兴趣的:(Android:开发实践,kotlin,android,java,日志打印)