Ich erstelle meine ersten Kotlin-Klassen in meiner Android-Anwendung. Normalerweise habe ich zu Protokollierungszwecken eine Konstante mit Namen TAG
. Was ich in Java tun würde, ist:
private static final String TAG = MyClass.class.getSimpleName();
Ich weiß, dass ich in Kotlin-Klassen auf folgende TAG
Weise erstellen kann:
private val TAG = MyClass::class.java.simpleName
Dies ist in Ordnung für Projekte, die Java und Kotlin verwenden. Was ist jedoch, wenn ich ein neues Projekt starte, das sich nur in Kotlin befindet? Wie kann ich dort TAG
Konstante definieren ? Gibt es mehr Kotlin-Wege, auf denen ich diese seltsame Konstruktion nicht habe class.java.simpleName
?
simpleName
ist riskant, wenn der Klassenname verschleiert ist.Antworten:
Im Allgemeinen sind Konstanten alle Kappen (z. B. FOO) und befinden sich im Begleitobjekt :
class MyClass { companion object { public const val FOO = 1 } }
und um das TAG-Feld zu definieren, können Sie Folgendes verwenden:
private val TAG = MyClass::class.qualifiedName
quelle
const
Werte müssen Kompilierungszeitkonstanten sein. Da Kotlin nichts Vergleichbares hatnameof
, kann es nicht garantieren, dass diese Aussage immer den gleichen Wert hat. Auch, wie Gabriele Mariotti sagte,const
wurde in der Antwort nicht verwendet.MyClass::class.qualifiedName
erfordert Hmm Reflexion, was die Komplexität der Anwendung erheblich erhöht und eine zusätzliche JAR-Datei erfordert. Gibt es einen einfacheren Weg, um diese ach so häufige Aufgabe zu erledigen?MyClass::class.java.simpleName
?Diese Erweiterung ermöglicht es uns, TAG in jeder Klasse zu verwenden
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")
Es wurde auch validiert, um als gültiges Android-Protokoll-Tag zu funktionieren.
quelle
In Kotlin können Sie eine Erweiterung erstellen und stattdessen das Tag als Methodenaufruf aufrufen. Dies würde bedeuten, dass Sie es niemals in jeder Klasse definieren müssen. Wir können es jedes Mal dynamisch erstellen, wenn wir die Methode aufrufen:
inline fun <reified T> T.TAG(): String = T::class.java.simpleName
quelle
Der allgemein vorgeschlagene Ansatz zur Verwendung der
companion object
generiert eine zusätzlichestatic final
Instanz einer Companion-Klasse und ist daher in Bezug auf Leistung und Speicher schlecht.Der beste Weg (IMHO)
Definieren Sie ein Protokoll-Tag als Konstante der obersten Ebene, sodass nur eine zusätzliche Klasse generiert wird (
MyClassKt
), aber im Vergleich dazucompanion object
gibt es keinestatic final
Instanz davon (und überhaupt keine Instanz):private const val TAG = "MyLogTag" class MyClass { fun logMe() { Log.w(TAG, "Message") } }
Andere Option
Verwenden Sie eine normale
val
. Obwohl dies ungewöhnlich erscheint, wenn ein Protokoll-Tag nicht als Konstante in Großbuchstaben angezeigt wird, werden dadurch keine Klassen generiert und der geringste Overhead verursacht.class MyClass { private val tag = "myLogTag" fun logMe() { Log.w(tag, "Message") } }
quelle
Einfach das Folgende zu tun hat bei mir funktioniert.
private val TAG = this::class.java.simpleName
quelle
companion object
?Ich möchte
TAG
eine Erweiterungsfunktion sein, wie von Fredy Mederos vorgeschlagen .Erweiterung seiner Antwort zur Unterstützung anonymer Klassen:
/** * 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 } }
quelle
Der beste Weg, um (imho) zu protokollieren, ist die Verwendung von Timber: https://github.com/JakeWharton/timber
Aber wenn Sie keine Bibliothek verwenden möchten, dann
TAG kann als Inline-Erweiterungseigenschaft definiert werden (z. B. in
Extensions.kt
):inline val <reified T> T.TAG: String get() = T::class.java.simpleName
Einige weitere Erweiterungen, um nicht ständig TAG zu schreiben in
Log.d(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)
Und dann können Sie sie in jeder Klasse verwenden:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) logd("Activity created") }
quelle
onCreate() { if (BuildConfig.DEBUG) Timber.plant(Timber.DebugTree()) }
und dann in jeder Klasse verwenden,Timber.d("msg")
ohne explizite LOG_TAG zu benötigenTAG
, Timber wurde bereits hinzugefügt.Sie können Ihre
TAG
durch@JvmField
wie folgt definieren:companion object { @JvmField val TAG: String = MyClass::class.java.simpleName }
Weitere Informationen finden Sie in diesem Artikel: Kotlins versteckte Kosten
quelle
Ich habe einige Protokollerweiterungsfunktionen erstellt, um zu vermeiden, dass das Protokoll-Tag wie in Java deklariert wird (möglicherweise weniger leistungsfähig, aber da wir über die Protokollierung sprechen, sollte dies IMO akzeptabel sein). Der Ansatz verwendet reifizierte Typparameter und andere Kotlin-Goodies, um den einfachen Klassennamen abzurufen. Hier ist ein einfaches Beispiel:
inline fun <reified T> T.logi(message: String) = Log.i(T::class.java.simpleName, message)
Eine ausführlichere Übersicht finden Sie hier
quelle
Antwort mit aktualisiert
Kotlin 1.2.20
class MyClass { companion object { @JvmField public val FOO = 1 } }
Verwendet
MyClass.FOO
quelle
Ich erstelle die Konstante als Begleitobjekt:
companion object { val TAG = "SOME_TAG_VALUE" }
Dann kann ich es so verwenden:
MyClass.TAG
quelle
Deklarieren Sie die TAG-Variable mit
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 } }
Verwenden Sie die Variable like
Log.d(YourClass.TAG, "Your message"); //or Log.e(TAG, "Your message");
quelle
::class.java.simpleName
, müssen Sie einschließenkotlin-reflect.jar
.Ich habe einen Weg gefunden, der mehr "Kopieren-Einfügen" -fähig ist, da Sie nicht den Namen Ihrer Klasse eingeben müssen:
package com.stackoverflow.mypackage class MyClass { companion object { val TAG = this::class.toString().split(".").last().dropLast(10) } }
Es ist nicht die eleganteste Lösung, aber es funktioniert.
this::class.toString().split(".").last()
wird dir geben,"com.stackoverflow.mypackage.MyClass$Companion"
damit du dasdropLast(10)
entfernen musst$Companion
.Alternativ können Sie dies tun:
package com.stackoverflow.mypackage class MyClass { val TAG = this::class.simpleName }
Dann ist die
TAG
Mitgliedsvariable jedoch nicht mehr "statisch" und folgt nicht den empfohlenen Namenskonventionen.quelle
Sie können dies versuchen:
companion object { val TAG = ClearCacheTask::class.java.simpleName as String }
quelle
AnkoLogger verwendet eine Schnittstelle, um das Protokoll-Tag zu definieren.
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") } }
Sie können es so verwenden:
class MyClass : AnkoLogger { fun someFun(){ info("logging info") } }
Vielleicht kann AnkoLogger Ihnen einige Ideen zur Implementierung eines benutzerdefinierten Protokollierungswerkzeugs geben.
quelle
In Android Studio können Sie normalerweise etwas umbenennen, indem Sie mit der rechten Maustaste auf den Namen klicken und Refactor-> Rename auswählen. Ich denke, es ist in Ordnung, so etwas zu tun.
class MyClass { companion object { private const LOG_TAG = "MyClass" } }
Wenn Sie die Klasse
MyClass
wie beschrieben umbenennen , schlägt die IDE vor, auch Ihren LOG_TAG-String umzubenennen.Letztendlich gibt es Vor- und Nachteile der Verwendung dieser Methode im Vergleich zu anderen Methoden. Da LOG_TAG ein String ist, müssen Sie die Datei kotlin-reflekt.jar nicht importieren, wie Sie es tun würden, wenn Sie
LOG_TAG
gleich setzenMyClass::class.simpleName
. Da die Variable mit demconst
Schlüsselwort als Konstante zur Kompilierungszeit deklariert wird, ist der generierte Bytecode kleiner, da keine weiteren versteckten Getter generiert werden müssen, wie in diesem Artikel beschrieben .quelle
Hier ist meine Erweiterungsfunktion in Kotlin. Fügen Sie sie einfach in Ihre Erweiterungsdatei ein.
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 } }
Dann können Sie TAG in jeder Klasse wie der folgenden verwenden:
Log.d(TAG, "country list")
quelle