在Kotlin中定义log TAG常量的最佳方法是什么?

时间:2017-08-23 13:25:29

标签: java android kotlin constants

我正在Android应用程序中创建我的第一个Kotlin类。通常为了记录目的,我有一个名为$hash_map{key} = \@arr 的常量。我在Java中会做的是:

TAG

我知道在Kotlin课程中我可以用这种方式创建private static final String TAG = MyClass.class.getSimpleName();

TAG

对于使用Java和Kotlin的项目来说这是可以的,但是如果我开始一个仅在Kotlin中的新项目呢?如何定义private val TAG = MyClass::class.java.simpleName 常数?有没有更多的Kotlin方式,我没有这种奇怪的结构TAG

18 个答案:

答案 0 :(得分:29)

一般来说常量都是大写字母(例如FOO)并且位于companion object

class MyClass {
    companion object {
        public const val FOO = 1

    }
}

并定义您可以使用的TAG字段:

private val TAG = MyClass::class.qualifiedName

答案 1 :(得分:18)

此扩展程序使我们可以在任何类中使用TAG

val Any.TAG: String
    get() {
        val tag = javaClass.simpleName
        return if (tag.length <= 23) tag else tag.substring(0, 23)
    }

//usage
Log.e(TAG,"some value")

它还经过验证可以用作Android有效的Log标签。

答案 2 :(得分:11)

通常建议使用companion object的方法生成伴侣类的额外static final实例,因此性能和内存都很差。

最好的方式(恕我直言)

将日志标记定义为顶级常量,因此只生成额外的类(MyClassKt),但与companion object进行比较时,它不会有static final个实例(和没有任何实例):

private const val TAG = "MyLogTag"

class MyClass {

    fun logMe() {
        Log.w(TAG, "Message")
    }
}

另一个选项

使用普通val。虽然看到日志标记不是全大写常量看起来很不寻常,但这不会生成任何类并且开销最小。

class MyClass {

    private val tag = "myLogTag"

    fun logMe() {
        Log.w(tag, "Message")
    }
}

答案 3 :(得分:8)

在Kotlin中,您可以创建扩展,然后将tag调用为方法调用。这意味着您不必在每个类中都定义它,我们每次调用该方法时都可以动态构造它:

inline fun <reified T> T.TAG(): String = T::class.java.simpleName

答案 4 :(得分:6)

只需执行以下操作即可。

private val TAG = this::class.java.simpleName

答案 5 :(得分:5)

您可以按TAG定义@JvmField,如下所示:

companion object {
    @JvmField val TAG: String = MyClass::class.java.simpleName
}

有关详细信息,请阅读以下文章:Kotlin's hidden costs

答案 6 :(得分:3)

我创建了一些Log扩展函数,以避免像我们在Java中那样声明log标记(可能性能较低,但是鉴于我们正在谈论日志记录,这应该是IMO)。该方法使用经过修饰的类型参数和其他Kotlin好吃的东西来检索类的简单名称。这是一个基本示例:

inline fun <reified T> T.logi(message: String) =
   Log.i(T::class.java.simpleName, message)

您可以找到更详细的要旨here

答案 7 :(得分:2)

使用Kotlin 1.2.20

更新了答案
class MyClass {
    companion object {

        @JvmField
        public val FOO = 1
    }
}

用途

MyClass.FOO

答案 8 :(得分:1)

我找到了一种更多&#34;复制粘贴&#34; -able的方式,因为它不要求您输入班级名称:

package com.stackoverflow.mypackage

class MyClass
{
    companion object {
        val TAG = this::class.toString().split(".").last().dropLast(10)
    }
}

它不是最优雅的解决方案,但它有效。

this::class.toString().split(".").last()会向您"com.stackoverflow.mypackage.MyClass$Companion",因此您需要dropLast(10)删除$Companion

或者你可以这样做:

package com.stackoverflow.mypackage

class MyClass
{
    val TAG = this::class.simpleName
}

但是TAG成员变量不再是&#34;静态&#34;并且不遵循建议的命名约定。

答案 9 :(得分:1)

使用val

声明TAG变量
class YourClass {
   companion object {
      //if use java and kotlin both in project
      //private val TAG = MyClass::class.java.simpleName

      //if use only kotlin in project
      private val TAG = YourClass::class.simpleName
   }
}

使用像

这样的变量
Log.d(YourClass.TAG, "Your message");
//or 
Log.e(TAG, "Your message");

答案 10 :(得分:1)

TAG可以定义为内联扩展属性:

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

并且不要一直在Log.d(TAG, "")中写TAG:

inline fun <reified T> T.logv(message: String) = Log.v(TAG, message)
inline fun <reified T> T.logi(message: String) = Log.i(TAG, message)
inline fun <reified T> T.logw(message: String) = Log.w(TAG, message)
inline fun <reified T> T.logd(message: String) = Log.d(TAG, message)
inline fun <reified T> T.loge(message: String) = Log.e(TAG, message)

答案 11 :(得分:0)

AnkoLogger使用接口来定义日志标记。

interface AnkoLogger {
            /**
             * The logger tag used in extension functions for the [AnkoLogger].
             * Note that the tag length should not be more than 23 symbols.
             */
            val loggerTag: String
                get() = getTag(javaClass)
        }
private fun getTag(clazz: Class<*>): String {
        val tag = clazz.simpleName
        return if (tag.length <= 23) {
            tag
        } else {
            tag.substring(0, 23)
        }
    }
inline fun AnkoLogger.info(message: () -> Any?) {
    val tag = loggerTag
    if (Log.isLoggable(tag, Log.INFO)) {
        Log.i(tag, message()?.toString() ?: "null")
    }
}

你可以像这样使用它:

class MyClass : AnkoLogger {
    fun someFun(){
       info("logging info")
    }
}

也许AnkoLogger可以为您提供实现自定义日志记录工具的一些想法。

答案 12 :(得分:0)

我将常量创建为伴侣对象:

companion object {
    val TAG = "SOME_TAG_VALUE"
}

然后,我可以这样使用它:

MyClass.TAG

答案 13 :(得分:0)

在Android Studio中,重命名的通常方法是右键单击名称,然后选择“重构”->“重命名”。所以,我认为做这样的事情很好,

class MyClass {
    companion object {
        private const LOG_TAG = "MyClass"
    }
}

因为如果您像我描述的那样重命名类MyClass,那么IDE也会建议重命名LOG_TAG字符串。

使用此方法与其他方法相比,最终有优缺点。由于LOG_TAG是字符串,因此无需导入kotlin-reflect.jar,就像将LOG_TAG设置为MyClass::class.simpleName一样。另外,由于使用const关键字将该变量声明为编译时常量,因此生成的字节码较小,因为它不需要生成更多的隐藏getter,如this article中所述。

答案 14 :(得分:0)

我喜欢TAG作为Fredy Mederos建议的扩展功能。

扩展他的答案以支持匿名类:

 /**
 * extension function to provide TAG value
 */
val Any.TAG: String
    get() {
        return if (!javaClass.isAnonymousClass) {
            val name = javaClass.simpleName
            if (name.length <= 23) name else name.substring(0, 23)// first 23 chars
        } else {
            val name = javaClass.name
            if (name.length <= 23) name else name.substring(name.length - 23, name.length)// last 23 chars
        }
    }

答案 15 :(得分:0)

您可以尝试以下方法:

companion object {
    val TAG = ClearCacheTask::class.java.simpleName as String
}

答案 16 :(得分:0)

这是我在kotlin中的扩展功能,只需将其添加到扩展文件中即可。

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)// first 23 chars
    } 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)// last 23 chars
    }
}

然后您可以在以下任何类中使用TAG:

Log.d(TAG, "country list")

答案 17 :(得分:0)

我定义了一个接口,它将 TAG 定义为具有默认 getter 实现的属性。 接口既可以由类“实现”,也可以由它的伴随对象“实现”:

//Prefix allows easier filtering in LogCat
private const val PREFIX = "somePrefix.";

interface HasLogTag {
    val TAG: String
        get() {
            val name = javaClass.canonicalName?.removeSuffix(".Companion")?.substringAfterLast(".")
            return "$PREFIX${name}"
        }
}

接口使用如下:

import yourPackage.HasLogTag     
....
class MyClass : HasLogTag {
    ...
    //Alternatively: Let the companion object "implement" the interface
    companion object : HasLogTag {
    ...
    Log.e(TAG, "Some Info)
}

由于每次使用都会调用 getter,因此为伴随对象定义 TAG 没有任何好处。

注意:在之前的版本中,我使用反射来找出是类本身还是伴随对象定义了接口。

然而,这似乎严重减慢了我的应用程序的启动速度。