Existe-t-il un moyen pratique de créer des classes de données Parcelables dans Android avec Kotlin?
J'utilise actuellement l'excellent AutoParcel dans mon projet Java, ce qui facilite la création de classes Parcelables.
Maintenant, Kotlin, que je considère pour mon prochain projet, a ce concept de classes de données, qui génèrent 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)?
12 réponses
Kotlin 1.1.4 est
Le plugin Android Extensions inclut désormais un générateur automatique D'implémentation Parcelable. Déclarez les propriétés sérialisées dans un constructeur principal et ajoutez une annotation @ Parcelize, et les méthodes writeToParcel()/createFromParcel() seront créées automatiquement:
@Parcelize
class User(val firstName: String, val lastName: String) : Parcelable
Vous devez donc les activer en ajoutant ceci à la construction de votre module.gradle :
apply plugin: 'org.jetbrains.kotlin.android.extensions'
android {
androidExtensions {
experimental = true
}
}
, Vous pouvez essayer ce plugin:
Android-parcelable-ide-plugin-kotlin
Il vous aide à générer du Code Standard Parcelable Android pour la classe de données de kotlin. Et ça ressemble enfin à ceci:
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)
}
}
}
}
Avez-vous essayé PaperParcel? C'est un processeur d'annotation qui génère automatiquement le code standard Android Parcelable
pour vous.
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 transmis directement à un Bundle
ou Intent
Edit: Mise à jour avec la dernière API
Le meilleurs façon avec non réutilisable le code est Contrebandier plugin gradle. Tout ce dont vous avez besoin est simplement d'implémenter L'interface AutoParcelable comme
data class Person(val name:String, val age:Int): AutoParcelable
Et c'est tout. Fonctionne aussi pour les classes scellées. Ce plugin fournit également la validation de la compilation pour toutes les classes AutoParcelable.
UPD 17.08.2017 Maintenant avec Kotlin 1.1.4 et Kotlin extensions Android plugin vous pouvez utiliser @Parcelize
annotation. Dans ce cas, l'exemple ci-dessus ressemblera à:
@Parcelize class Person(val name:String, val age:Int): Parcelable
Pas besoin de data
modificateur. Le plus grand inconvénient, pour l'instant, est d'utiliser le plugin Kotlin-Android-extensions qui a beaucoup d'autres fonctions qui pourraient être inutiles.
Il suffit de cliquer 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"
Je vais laisser ma façon de faire au cas où cela pourrait aider quelqu'un.
Ce que je fais c'est que j'ai un générique Parcelable
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 parcelables 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 ce remplacement standard.
Malheureusement, il n'y a aucun moyen dans Kotlin de mettre un vrai champ dans une interface, donc vous ne pouvez pas l'hériter d'un adaptateur d'interface gratuitement:
data class Par : MyParcelable
Vous pouvez regarder la délégation, mais cela n'aide pas avec les champs, AFAIK: https://kotlinlang.org/docs/reference/delegation.html
Donc, la seule option que je vois est une fonction de tissu pour Parcelable.Creator
, ce qui est assez évident.
Je préfère simplement utiliser le https://github.com/johncarl81/parceler lib avec
@Parcel(Parcel.Serialization.BEAN)
data class MyClass(val value)
En Utilisant Android Studio et le pluginKotlin , j'ai trouvé un moyen facile de convertir mes anciens Java Parcelable
s avec Pas de plugins supplémentaires (Si tout ce que vous voulez est de transformer une toute nouvelle classe data
en Parcelable
, passez à l'extrait de code 4ème).
Disons que vous avez une classe Person
avec toute la plaque de 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 Java simple et ancien (les propriétés doivent être finales et défini 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;
}
}
Alors 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 cela en un Parcelable
à nouveau. Passez 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 voir, l'implémentation Parcelable
est un code généré automatiquement ajouté à votre définition de classe data
.
Notes:
- Essayer de convertir un Java
Parcelable
directement dans Kotlin ne produira pas le même résultat avec la version actuelle de la Kotlin plugin (1.1.3
). - j'ai dû enlever quelques accolades supplémentaires que le générateur de code actuel
Parcelable
introduit. Doit être un bug mineur.
J'espère que cette astuce fonctionne pour vous aussi bien que pour moi.
Il y a un Plugin mais n'est pas toujours aussi mis à 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 en utilisant Parcelable
et des listes:
Classes de données utilisant Parcelable avec des listes:
J'espère que ça aide!
Kotlin a rendu l'ensemble du processus de Parcélisation dans Android sacrément facile avec son annotation @Parcel.
Pour ce faire
Étape 1. Ajoutez des extensions Kotlin dans votre module d'application gradle
Étape 2. Ajouter experimental = true puisque cette fonctionnalité est encore en expérimentation dans gradle.
AndroidExtensions { expérimental = vrai }
Étape 3. annoncer la classe de données avec @ Parcel
Ici est un exemple simple sur l'utilisation de @Parcel
Kotlin a rendu l'ensemble du processus de Parcélisation dans Android sacrément facile avec son annotation @Parcel.
Pour ce faire
Étape 1. Ajoutez des extensions Kotlin dans votre module d'application gradle
Étape 2. Ajouter experimental = true puisque cette fonctionnalité est encore en expérimentation dans gradle.
AndroidExtensions { expérimental = vrai }
Étape 3. annoncer la classe de données avec @ Parcel
Ici est un exemple simple sur l'utilisation de @Parcel dans Kotlin pour transmettre des données entre les composants Android.