Je crée mes premières classes de Kotlin dans mon application Android. Habituellement, à des fins de journalisation, j'ai une constante portant le nom TAG
. Ce que je ferais en Java, c'est:
private static final String TAG = MyClass.class.getSimpleName();
Je sais que dans les classes Kotlin, je peux créer TAG
de cette façon:
private val TAG = MyClass::class.Java.simpleName
Cela convient aux projets utilisant Java et Kotlin, mais que se passe-t-il si je lance un nouveau projet uniquement dans Kotlin? Comment puis-je définir là TAG
constante? Y a-t-il plus de manière Kotlin où je n'ai pas cette construction class.Java.simpleName
étrange?
En général, les constantes sont toutes en majuscules (ex. FOO) et situées dans le objet compagnon :
class MyClass {
companion object {
public const val FOO = 1
}
}
et pour définir le champ TAG, vous pouvez utiliser:
private val TAG = MyClass::class.qualifiedName
Cette extension nous permet d’utiliser TAG dans n’importe quelle classe
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")
Il a également validé pour fonctionner comme une balise de journal valide Android.
Dans Kotlin, vous pouvez créer une extension et appeler tag en tant qu'appel de méthode. Cela signifierait que vous n'auriez jamais à le définir à l'intérieur de chaque classe, nous pouvons le construire dynamiquement chaque fois que nous appelons la méthode:
inline fun <reified T> T.TAG(): String = T::class.Java.simpleName
Faire simplement ce qui suit a fonctionné pour moi.
private val TAG = this::class.Java.simpleName
L’approche généralement suggérée d’utiliser le companion object
génère une instance supplémentaire de static final
d’une classe compagnon, ce qui nuit aux performances et à la mémoire.
Définissez une balise de journal comme une constante de niveau supérieur. Ainsi, seule une classe supplémentaire est générée (MyClassKt
). Toutefois, par rapport à companion object
, il n'y aura pas d'instance static final
(et aucune instance que ce soit):
private const val TAG = "MyLogTag"
class MyClass {
fun logMe() {
Log.w(TAG, "Message")
}
}
Utilisez une val
normale. Bien que cela semble inhabituel de voir une balise de journal pas comme une constante majuscule, cela ne générera aucune classe et entraînera un minimum de temps système.
class MyClass {
private val tag = "myLogTag"
fun logMe() {
Log.w(tag, "Message")
}
}
Vous pouvez définir votre TAG
par @JvmField
comme ci-dessous:
companion object {
@JvmField val TAG: String = MyClass::class.Java.simpleName
}
Pour plus de détails, vous pouvez lire cet article: Les coûts cachés de Kotlin
J'ai créé certaines fonctions d'extension de journal pour éviter de déclarer la balise de journal comme nous le faisions en Java (peut-être moins performant, mais étant donné que nous parlons de journalisation, cela devrait être un IMO acceptable). Cette approche utilise des paramètres de type réifiés et d’autres goodies Kotlin pour récupérer le nom simple de la classe. Voici un exemple de base:
inline fun <reified T> T.logi(message: String) =
Log.i(T::class.Java.simpleName, message)
Vous pouvez trouver un Gist plus élaboré ici
Réponse mise à jour avec Kotlin 1.2.20
class MyClass {
companion object {
@JvmField
public val FOO = 1
}
}
les usages
MyClass.FOO
J'ai trouvé un moyen qui est plus "copier-coller", puisqu'il ne vous oblige pas à taper le nom de votre classe:
package com.stackoverflow.mypackage
class MyClass
{
companion object {
val TAG = this::class.toString().split(".").last().dropLast(10)
}
}
Ce n'est pas la solution la plus élégante mais ça marche.
this::class.toString().split(".").last()
vous donnera "com.stackoverflow.mypackage.MyClass$Companion"
donc vous avez besoin de la dropLast(10)
pour supprimer $Companion
.
Sinon, vous pouvez le faire:
package com.stackoverflow.mypackage
class MyClass
{
val TAG = this::class.simpleName
}
Mais alors la variable membre TAG
n'est plus "statique" et ne respecte pas les conventions de dénomination recommandées.
Déclarez la variable TAG avec 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
}
}
Utilisez la variable comme
Log.d(YourClass.TAG, "Your message");
//or
Log.e(TAG, "Your message");
Dans Android Studio, la méthode habituelle pour renommer un élément consiste à cliquer avec le bouton droit de la souris sur le nom, sélectionnez Refactor> Renommer. Donc, je pense que c'est bien de faire quelque chose comme ça,
class MyClass {
companion object {
private const LOG_TAG = "MyClass"
}
}
car si vous renommez la classe MyClass
comme je l'ai décrit, alors IDE suggérera de renommer également votre chaîne LOG_TAG.
En fin de compte, il y a des avantages et des inconvénients à utiliser cette méthode par rapport à d'autres méthodes. LOG_TAG étant une chaîne, il n'est pas nécessaire d'importer le fichier kotlin-reflect.jar, comme vous le feriez si vous définissez LOG_TAG
égal à MyClass::class.simpleName
. De plus, comme la variable est déclarée comme une constante de compilation avec le mot clé const
, le bytecode généré est plus petit puisqu'il n'est pas nécessaire de générer plus de getters cachés, comme décrit dans cet article .
AnkoLogger utilise une interface pour définir la balise de journal.
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")
}
}
Vous pouvez l'utiliser comme ceci:
class MyClass : AnkoLogger {
fun someFun(){
info("logging info")
}
}
Peut-être qu'AnkoLogger peut vous donner quelques idées pour implémenter un outil de journalisation personnalisé.
Je crée la constante en tant qu'objet compagnon:
companion object {
val TAG = "SOME_TAG_VALUE"
}
Ensuite, je peux l'utiliser comme ça:
MyClass.TAG