240 votes

Comment créer un constructeur vide pour une classe de données dans Kotlin Android ?

J'ai plus de 10 variables déclarées dans une classe de données Kotlin, et je voudrais créer un constructeur vide pour cette classe, comme on le fait généralement en Java.

Classe de données :

data class Activity(
    var updated_on: String,
    var tags: List<String>,
    var description: String,
    var user_id: List<Int>,
    var status_id: Int,
    var title: String,
    var created_at: String,
    var data: HashMap<*, *>,
    var id: Int,
    var counts: LinkedTreeMap<*, *>,
)

Utilisation prévue :

val activity =  Activity();
activity.title = "New Computer"
sendToServer(activity)

Mais la classe de données exige que tous les arguments soient passés lors de la création d'un constructeur. Comment pouvons-nous simplifier cela comme le constructeur de la classe POJO de Java ?

val activity =  Activity(null,null,null,null,null,"New Computer",null,null,null,null)
sendToServer(activity)

313voto

miensol Points 1889

Vous avez deux options ici :

  1. Attribuez une valeur par défaut à chaque constructeur primaire paramètre :

    data class Activity(
        var updated_on: String = "",
        var tags: List<String> = emptyList(),
        var description: String = "",
        var user_id: List<Int> = emptyList(),
        var status_id: Int = -1,
        var title: String = "",
        var created_at: String = "",
        var data: HashMap<*, *> = hashMapOf<Any, Any>(),
        var id: Int = -1,
        var counts: LinkedTreeMap<*, *> = LinkedTreeMap<Any, Any>()
    ) 
  2. Déclarer un constructeur secondaire qui n'a pas de paramètres :

    data class Activity(
        var updated_on: String,
        var tags: List<String>,
        var description: String,
        var user_id: List<Int>,
        var status_id: Int,
        var title: String,
        var created_at: String,
        var data: HashMap<*, *>,
        var id: Int,
        var counts: LinkedTreeMap<*, *>
    ) {
        constructor() : this("", emptyList(), 
                             "", emptyList(), -1, 
                             "", "", hashMapOf<Any, Any>(), 
                             -1, LinkedTreeMap<Any, Any>()
                             )
    }

Si vous ne comptez pas sur copy o equals de la Activity ou n'utilisez pas la classe autogénérée data class vous pourriez utiliser une classe normale comme ceci :

class ActivityDto {
    var updated_on: String = "",
    var tags: List<String> = emptyList(),
    var description: String = "",
    var user_id: List<Int> = emptyList(),
    var status_id: Int = -1,
    var title: String = "",
    var created_at: String = "",
    var data: HashMap<*, *> = hashMapOf<Any, Any>(),
    var id: Int = -1,
    var counts: LinkedTreeMap<*, *> = LinkedTreeMap<Any, Any>()
}

Pas tous les DTO doit être un data class et vice versa. En fait, d'après mon expérience, je trouve que les classes de données sont particulièrement utiles dans les domaines qui impliquent une logique commerciale complexe.

1 votes

Merci @miensol, Y a-t-il un moyen de faire cela en utilisant la copie amusante, par exemple. kotlinlang.org/docs/reference/data-classes.html#copying

0 votes

@SaiKiran à utiliser copy vous avez besoin d'une instance de classe de données. Pour la créer, vous devez invoquer un constructeur - et c'est là que le bât blesse.

0 votes

J'utilise Kotlin 1.1.2 pour Android Studio 2.3 et emptyList n'est pas disponible :/

86voto

kosiara Points 81

Si vous donnez valeurs par défaut pour tous les champs - Le constructeur vide est généré automatiquement par Kotlin.

data class User(var id: Long = -1,
                var uniqueIdentifier: String? = null)

et vous pouvez simplement appeler :

val user = User()

1 votes

Si l'identifiant est généré automatiquement, comment l'utiliser ?

1 votes

Ça a marché pour moi. Pour le message Firebase Chat : class FeelComChatMessage (messageText: String = "", messageUser: String = "")

0 votes

@Panchal Amit Qui génère automatiquement l'identité ? Room ? Vous devriez étudier ses annotations je pense.

16voto

Gui13 Points 3568

Parallèlement à la réponse de @miensol, permettez-moi d'ajouter quelques détails :

Si vous voulez un constructeur vide visible en Java en utilisant des classes de données, vous devez le définir explicitement.

Utiliser les valeurs par défaut + le spécificateur de constructeur est assez facile :

data class Activity(
    var updated_on: String = "",
    var tags: List<String> = emptyList(),
    var description: String = "",
    var user_id: List<Int> = emptyList(),
    var status_id: Int = -1,
    var title: String = "",
    var created_at: String = "",
    var data: HashMap<*, *> = hashMapOf<Any, Any>(),
    var id: Int = -1,
    var counts: LinkedTreeMap<*, *> = LinkedTreeMap<Any, Any>()
) {
    constructor() : this(title = "") // this constructor is an explicit
                                     // "empty" constructor, as seen by Java.
}

Cela signifie qu'avec cette astuce, vous pouvez maintenant sérialiser/désérialiser cet objet avec les sérialiseurs Java standard (Jackson, Gson, etc.).

0 votes

La dernière recommandation est fausse. Au moins pour le sérialiseur Gson, en fait, Gson utilise le mécanisme unsafe pour créer des objets et il n'appellera pas votre constructeur. Je viens de répondre à une question connexe ici stackoverflow.com/questions/59390294/

16voto

mxml Points 192

La réponse moderne à cette question devrait être l'utilisation de l'outil de Kotlin, le no-arg compiler plugin ce qui crée un code de construction sans argument pour les apies classiques plus d'infos ici

il suffit d'ajouter le chemin de la classe du plugin au niveau du projet build.gradle

    dependencies {
    ....

    classpath "org.jetbrains.kotlin:kotlin-noarg:1.4.10"

    ....
    }

puis configurez votre annotation pour générer le no-arg Constructeur

apply plugin: "kotlin-noarg"

noArg {
      annotation("your.path.to.annotaion.NoArg")
      invokeInitializers = true
}

puis définissez votre fichier d'annotation NoArg.kt

 @Target(AnnotationTarget.CLASS)
 @Retention(AnnotationRetention.SOURCE)
 annotation class NoArg

enfin, dans toute classe de données, vous pouvez simplement utiliser votre propre annotation

@NoArg
data class SomeClass( val datafield:Type , ...   )

J'avais l'habitude de créer mes propres no-arg Le constructeur est la réponse acceptée, ce que j'ai obtenu en cherchant, mais ensuite ce plugin est sorti ou quelque chose comme ça et je l'ai trouvé beaucoup plus propre.

9voto

yOshi Points 29

Si vous donnez une valeur par défaut à chaque paramètre primaire du constructeur :

data class Item(var id: String = "",
            var title: String = "",
            var condition: String = "",
            var price: String = "",
            var categoryId: String = "",
            var make: String = "",
            var model: String = "",
            var year: String = "",
            var bodyStyle: String = "",
            var detail: String = "",
            var latitude: Double = 0.0,
            var longitude: Double = 0.0,
            var listImages: List<String> = emptyList(),
            var idSeller: String = "")

et à partir de la classe où les instances vous pouvez l'appeler sans arguments ou avec les arguments que vous avez à ce moment-là.

var newItem = Item()

var newItem2 = Item(title = "exampleTitle",
            condition = "exampleCondition",
            price = "examplePrice",
            categoryId = "exampleCategoryId")

0 votes

Comment gérer cela lorsque nous passons la valeur du contexte.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X