用Kotlin在Android中创建Parcelable数据类有没有一种方便的方法?

我目前在我的Java项目中使用了优秀的AutoParcel ,这有助于创建Parcelable类。

现在,我为下一个项目考虑的Kotlin具有这种数据类的概念,它自动生成equals,hashCode和toString方法。

有没有一种方便的方法来创建一个Kotlin数据类Parcelable方便的方式(没有手动实现的方法)?

Kotlin 1.1.4已经出来了

Android扩展插件现在包含一个自动Parcelable实现生成器。 在主构造函数中声明序列化的属性,并添加一个@Parcelize注解,并自动创建writeToParcel()/ createFromParcel()方法:

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

所以你需要启用他们添加到你build.gradle

 apply plugin: 'org.jetbrains.kotlin.android.extensions' androidExtensions { experimental = true } 

你可以试试这个插件:

Android的parcelable-的IntelliJ-插件,科特林

它可以帮助您为kotlin的数据类生成Android Parcelable样板代码。 最后看起来像这样:

 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) } } } } 

你有没有试过PaperParcel ? 这是一个注释处理器,可以为您自动生成Android Parcelable样板代码。

用法:

使用@PaperParcel注释数据类,实现PaperParcelable ,并添加生成的CREATOR的JVM静态实例,例如:

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

现在你的数据类是Parcelable ,可以直接传递给BundleIntent

编辑:更新与最新的API

没有样板代码的最好方法是走私者 gradle插件。 你所需要的只是实现AutoParcelable接口

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

就这样。 也适用于密封课程。 此插件也为所有AutoParcelable类提供编译时验证。

UPD 17.08.2017现在使用Kotlin 1.1.4和Kotlin Android扩展插件,你可以使用@Parcelize注解。 在这种情况下,上面的例子看起来像这样:

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

不需要data修改器。 目前最大的缺点是使用kotlin-android-extensions插件,这个插件有许多其他功能可能是不必要的。

我会离开我的方式,以防万一它可能帮助某人。

我所做的是我有一个通用的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) } 

然后我创建这样的可能的包装:

 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()) } } } 

这让我摆脱了样板覆盖。

不幸的是,Kotlin没有办法在界面中放置一个真实的字段,所以你不能从一个接口适配器中继承它: data class Par : MyParcelable

你可以看一下代表团,但是对领域没有帮助,AFAIK: https : //kotlinlang.org/docs/reference/delegation.html

所以我看到的唯一选择是Parcelable.Creator一个结构函数,这是显而易见的。

我更喜欢使用https://github.com/johncarl81/parceler lib

 @Parcel(Parcel.Serialization.BEAN) data class MyClass(val value) 

使用Android StudioKotlin插件,我发现了一种简单的方法来转换旧的Java Parcelable而不需要额外的插件 (如果您只想将全新的data类转换为Parcelable ,请跳至第四个代码段)。

假设你有一个Person类,所有的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; } } 

从剥离Parcelable实现开始,留下一个简单的,简单的旧Java对象(属性应该是final的,并由构造函数设置):

 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; } } 

然后让Code > Convert Java file to Kotlin File选项做它的魔力:

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

将其转换为data类:

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

最后,我们Parcelable它变成一个Parcelable 。 悬停类名和Android Studio应该给你选择Add Parcelable Implementation 。 结果应该是这样的:

 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) } } } 

正如你所看到的, Parcelable实现是一些自动生成的代码附加到你的data类定义。

笔记:

  1. 尝试将Java Parcelable直接转换为Kotlin不会产生与当前版本的Kotlin插件( 1.1.3 )相同的结果。
  2. 当前的Parcelable代码生成器引入了一些额外的大括号。 必须是一个小错误。

我希望这个技巧对你有用,也对我有用。

有一个插件,但并不总是像Kotlin正在发展一样: https : //plugins.jetbrains.com/plugin/8086

另类:我有一个自定义数据类使用Parcelable和列表的工作示例:

使用Parcelable与Lists的数据类:

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

希望它有帮助!