Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/208.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在Kotlin中定义日志标记常量的最佳方法是什么?_Java_Android_Kotlin_Constants - Fatal编程技术网

Java 在Kotlin中定义日志标记常量的最佳方法是什么?

Java 在Kotlin中定义日志标记常量的最佳方法是什么?,java,android,kotlin,constants,Java,Android,Kotlin,Constants,我正在Android应用程序中创建我的第一个Kotlin类。通常出于日志记录的目的,我有一个名为TAG的常量。我在Java中要做的是: private static final String TAG = MyClass.class.getSimpleName(); 我知道在Kotlin类中,我可以通过以下方式创建标记: private val TAG = MyClass::class.java.simpleName 这对于使用Java和Kotlin的项目来说是可以的,但是如果我启动一个只在K

我正在Android应用程序中创建我的第一个Kotlin类。通常出于日志记录的目的,我有一个名为
TAG
的常量。我在Java中要做的是:

private static final String TAG = MyClass.class.getSimpleName();
我知道在Kotlin类中,我可以通过以下方式创建
标记

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

这对于使用Java和Kotlin的项目来说是可以的,但是如果我启动一个只在Kotlin中的新项目呢?如何定义那里的
标记
常量?还有没有更多的Kotlin方法,我没有这个奇怪的构造
class.java.simpleName

我正在创建常量作为一个伴随对象:

companion object {
    val TAG = "SOME_TAG_VALUE"
}
//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}"
        }
}
然后,我可以这样使用它:

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

通常,常数均为大写(例如FOO),位于:

要定义标记字段,可以使用:

private val TAG = MyClass::class.qualifiedName

val

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");

我找到了一种更能“复制粘贴”的方法,因为它不需要您键入类的名称:

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
}
但是,
标记
成员变量不再是“静态的”,并且不遵循推荐的命名约定。

使用接口定义日志标记

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")
    }
}

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

您可以通过
@JvmField
定义
标记,如下所示:

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

有关更多详细信息,请阅读本文:

更新了Kotlin 1.2.20的答案

class MyClass {
    companion object {

        @JvmField
        public val FOO = 1
    }
}
使用


通常建议使用
伴生对象
的方法会生成伴生类的额外
静态最终
实例,因此性能和内存方面都很差

最佳方式(IMHO) 将日志标记定义为顶级常量,这样只会生成额外的类(
MyClassKt
),但与
伴生对象
相比,它不会有
静态最终
实例(也不会有任何实例):

另一种选择 使用正常的
val
。虽然将日志标记视为不全大写常量看起来很不寻常,但这不会生成任何类,并且开销最小

class MyClass {

    private val tag = "myLogTag"

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

简单地做下面的工作对我来说很有效

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

我创建了一些日志扩展函数,以避免像在Java中那样声明日志标记(可能性能较差,但考虑到我们讨论的是日志记录,这应该是可以接受的)。该方法使用具体化的类型参数和其他Kotlin工具来检索类的简单名称。以下是一个基本示例:

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

你可以在Android Studio中找到更详细的要点,重命名的常用方法是右键单击名称,选择重构->重命名。所以,我认为这样做很好

class MyClass {
    companion object {
        private const LOG_TAG = "MyClass"
    }
}
因为如果像我描述的那样重命名类
MyClass
,那么IDE也会建议重命名日志标记字符串


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

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

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

此扩展允许我们在任何类中使用标记

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")
val Any.TAG:String
得到(){
val tag=javaClass.simpleName

返回if(tag.lengthI喜欢
tag
作为扩展函数

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

 /**
 * 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
        }
    }
/**
*提供标签值的扩展函数
*/
val Any.TAG:String
得到(){
如果(!javaClass.isAnonymousClass)返回{
val name=javaClass.simpleName
如果(name.length最好的伐木方式(imho)是使用木材:

但若你们不想使用图书馆,那个么

标记可以定义为内联扩展属性(例如在
Extensions.kt
中):

然后您可以在任何类中使用它们:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    logd("Activity created")
}
您可以尝试以下方法:

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

这是我在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
    }
}

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

companion object {
    val TAG = "SOME_TAG_VALUE"
}
//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,因此为伴随对象定义标记没有任何好处

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


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

MyClass::class.qualifiedName返回字符串,因此它显示常量有错误…该怎么办?@EnamulHaque
const
值必须是编译时常量。由于Kotlin没有类似于
nameof
的语句,因此它不能保证该语句始终具有相同的值另外,正如Gabriele Mariotti所说,
const
没有在答案中使用。嗯,根据Android Studio的警告,
MyClass::class.qualifiedName
需要反射,这大大增加了应用程序的复杂性并需要额外的jar文件。有没有更简单的方法来完成这项如此常见的任务
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
    }
}
Log.d(TAG, "country list")
//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)
}