web-dev-qa-db-fra.com

Existe-t-il un moyen pratique de créer des classes de données Parcelable dans Android avec Kotlin?

J'utilise actuellement l'excellent AutoParcel dans mon projet Java, qui facilite la création de classes Parcelable.

Maintenant, Kotlin, que je considère pour mon prochain projet, a ce concept de classes de données, qui génère automatiquement les méthodes equals, hashCode et toString.

Existe-t-il un moyen pratique de rendre une classe de données Kotlin Parcelable de manière pratique (sans implémenter les méthodes manuellement)?

85
thalesmello

Kotlin 1.1.4 est sorti

Le plugin Android Extensions inclut désormais un générateur d'implémentation automatique Parcelable. Déclarez les propriétés sérialisées dans un constructeur principal et ajoutez une annotation @Parcelize. Les méthodes writeToParcel ()/createFromParcel () seront automatiquement créées:

@Parcelize
class User(val firstName: String, val lastName: String) : Parcelable

Vous devez donc les activer en ajoutant ceci à votre build.gradle:

apply plugin: 'org.jetbrains.kotlin.Android.extensions'

Android {
    androidExtensions {
        experimental = true
    }
}
125
Dhaval Jivani

Vous pouvez essayer ce plugin:

Android-parcelable-intellij-plugin-kotlin

Il vous aide à générer du code standard Android Parcelable pour la classe de données de kotlin. Et ça ressemble finalement à ça:

data class Model(var test1: Int, var test2: Int): Parcelable {

    constructor(source: Parcel): this(source.readInt(), source.readInt())

    override fun describeContents(): Int {
        return 0
    }

    override fun writeToParcel(dest: Parcel?, flags: Int) {
        dest?.writeInt(this.test1)
        dest?.writeInt(this.test2)
    }

    companion object {
        @JvmField final val CREATOR: Parcelable.Creator<Model> = object : Parcelable.Creator<Model> {
            override fun createFromParcel(source: Parcel): Model{
                return Model(source)
            }

            override fun newArray(size: Int): Array<Model?> {
                return arrayOfNulls(size)
            }
        }
    }
}
43
nekocode

Avez-vous essayé PaperParcel ? C'est un processeur d'annotation qui génère automatiquement le code Android Parcelable.

Utilisation:

Annotez votre classe de données avec @PaperParcel, implémentez PaperParcelable et ajoutez une instance statique JVM du CREATOR généré, par exemple:

@PaperParcel
data class Example(
  val test: Int,
  ...
) : PaperParcelable {
  companion object {
    @JvmField val CREATOR = PaperParcelExample.CREATOR
  }
}

Maintenant, votre classe de données est Parcelable et peut être passée directement à Bundle ou Intent

Edit: Mise à jour avec la dernière API

19
Bradley Campbell

Le moyen meilleur avec le code pas de passe-partout est Smuggler gradle plugin. Tout ce dont vous avez besoin est simplement de mettre en œuvre une interface AutoParcelable comme

data class Person(val name:String, val age:Int): AutoParcelable

Et c'est tout. Fonctionne également pour les cours scellés. De plus, ce plugin fournit la validation de la compilation pour toutes les classes AutoParcelable. 

UPD 17.08.2017 Maintenant avec Kotlin 1.1.4 et le plug-in d'extensions Kotlin Android vous pouvez utiliser l'annotation @Parcelize. Dans ce cas, l'exemple ci-dessus ressemblera à ceci:

@Parcelize class Person(val name:String, val age:Int): Parcelable

Pas besoin de modificateur data. Le plus gros inconvénient, pour l’instant, est l’utilisation du plug-in kotlin-Android-extensions, qui comporte de nombreuses autres fonctions inutiles.

14
Stepango

Cliquez simplement sur le mot-clé data de votre classe de données kotlin, puis appuyez sur alt + Entrée, sélectionnez la première option en disant "Add Parceable Implementation"

12
M_P

Je vais laisser ma façon de faire au cas où cela pourrait aider quelqu'un.

Ce que je fais est que j'ai un Parcelable générique

interface DefaultParcelable : Parcelable {
    override fun describeContents(): Int = 0

    companion object {
        fun <T> generateCreator(create: (source: Parcel) -> T): Parcelable.Creator<T> = object: Parcelable.Creator<T> {
            override fun createFromParcel(source: Parcel): T = create(source)

            override fun newArray(size: Int): Array<out T>? = newArray(size)
        }

    }
}

inline fun <reified T> Parcel.read(): T = readValue(T::class.javaClass.classLoader) as T
fun Parcel.write(vararg values: Any?) = values.forEach { writeValue(it) }

Et puis je crée des parcelles comme ceci:

data class MyParcelable(val data1: Data1, val data2: Data2) : DefaultParcelable {
    override fun writeToParcel(dest: Parcel, flags: Int) { dest.write(data1, data2) }
    companion object { @JvmField final val CREATOR = DefaultParcelable.generateCreator { MyParcelable(it.read(), it.read()) } }
}

Ce qui me débarrasse de cette déroute.

4
gmemario

Malheureusement, Kotlin n'a aucun moyen de mettre un champ réel dans une interface. Vous ne pouvez donc pas l'hériter gratuitement d'un adaptateur d'interface: data class Par : MyParcelable

Vous pouvez regarder la délégation, mais cela n'aide pas avec les champs, autant que je sache, https://kotlinlang.org/docs/reference/delegation.html

Donc, la seule option que je vois est une fonction de structure pour Parcelable.Creator, ce qui est assez évident.

3
voddan

En utilisant Android Studio et le plug-in Kotlin, j'ai trouvé un moyen simple de convertir mon ancien fichier Java Parcelables avec aucun plugin supplémentaire (si vous ne voulez que transformer une nouvelle classe data en un Parcelable, passez au quatrième extrait de code). 

Supposons que vous avez une classe Person avec toutes les plaques de la chaudière Parcelable:

public class Person implements Parcelable{
    public static final Creator<Person> CREATOR = new Creator<Person>() {
        @Override
        public Person createFromParcel(Parcel in) {
            return new Person(in);
        }

        @Override
        public Person[] newArray(int size) {
            return new Person[size];
        }
    };

    private final String firstName;
    private final String lastName;
    private final int age;

    public Person(String firstName, String lastName, int age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }

    protected Person(Parcel in) {
        firstName = in.readString();
        lastName = in.readString();
        age = in.readInt();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(firstName);
        dest.writeString(lastName);
        dest.writeInt(age);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public int getAge() {
        return age;
    }
}

Commencez par supprimer l’implémentation Parcelable en laissant un objet nue, simple et ancien Java (les propriétés doivent être définitives et définies par le constructeur):

public class Person {
    private final String firstName;
    private final String lastName;
    private final int age;

    public Person(String firstName, String lastName, int age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public int getAge() {
        return age;
    }
}

Puis laissez l’option Code > Convert Java file to Kotlin File faire sa magie:

class Person(val firstName: String, val lastName: String, val age: Int)

Convertissez ceci en une classe data:

data class Person(val firstName: String, val lastName: String, val age: Int)

Et enfin, transformons à nouveau ceci en un Parcelable. Survolez le nom de la classe et Android Studio devrait vous donner l'option Add Parcelable Implementation. Le résultat devrait ressembler à ceci:

data class Person(val firstName: String, val lastName: String, val age: Int) : Parcelable {
    constructor(parcel: Parcel) : this(
            parcel.readString(),
            parcel.readString(),
            parcel.readInt()
    )

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeString(firstName)
        parcel.writeString(lastName)
        parcel.writeInt(age)
    }

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator<Person> {
        override fun createFromParcel(parcel: Parcel): Person {
            return Person(parcel)
        }

        override fun newArray(size: Int): Array<Person?> {
            return arrayOfNulls(size)
        }
    }
}

Comme vous pouvez le constater, l'implémentation Parcelable est un code généré automatiquement qui est ajouté à la définition de votre classe data.

Remarques:  

  1. Essayer de convertir un fichier JavaParcelable directement en Kotlin ne produira pas le même résultat avec la version actuelle du plug-in Kotlin (1.1.3).
  2. J'ai dû supprimer quelques accolades supplémentaires introduites par le générateur de code Parcelable actuel. Doit être un bug mineur. 

J'espère que cette astuce fonctionne pour vous aussi bien que pour moi.

3
argenkiwi

je préfère simplement utiliser le https://github.com/johncarl81/parceler lib avec 

@Parcel(Parcel.Serialization.BEAN)
data class MyClass(val value)
2
Jan Rabe
  • Utilisez l'annotation @ Parcelize au-dessus de votre classe Model/Data
  • Utiliser la dernière version de Kotlin
  • Utiliser la dernière version de Kotlin Android Extensions dans votre module d'application

Exemple :

@Parcelize
data class Item(
    var imageUrl: String,
    var title: String,
    var description: Category
) : Parcelable
1
Manoj Bhadane

Avec son annotation @Parcel, Kotlin a rendu l’ensemble du processus de parcellisation sous Android extrêmement facile.

Pour faire ça

Étape 1. Ajoutez des extensions Kotlin dans votre module gradué

Étape 2. Ajoutez experimental = true puisque cette fonctionnalité est toujours en cours d’expérimentation.

androidExtensions { expérimental = vrai }

Étape 3. Annoncer la classe de données avec @Parcel

Here est un exemple simple d'utilisation de @Parcel

0
Ramakrishna Joshi

Il existe un plugin, mais il n’est pas toujours aussi à jour que Kotlin évolue: https://plugins.jetbrains.com/plugin/8086

Alternative: J'ai un exemple de travail d'une classe de données personnalisée utilisant Parcelable et des listes:

Classes de données utilisant Parcelable avec des listes:

https://Gist.github.com/juanchosaravia/0b61204551d4ec815bbf

J'espère que ça aide!

0
Juancho