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

tha*_*llo 103 android parcelable kotlin

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

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

有没有一种方便的方法可以方便地使Kotlin数据类Parcelable(不手动实现方法)?

Dha*_*ani 157

Kotlin 1.1.4已经发布

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

@Parcelize
class User(val firstName: String, val lastName: String) : Parcelable
Run Code Online (Sandbox Code Playgroud)

所以你需要启用它们将它添加到模块的build.gradle中:

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

android {
    androidExtensions {
        experimental = true
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 编译器抱怨`这个calss实现Parcelable但不提供CREATOR字段`.你的答案是否足够(完整)? (9认同)
  • 您可以使用`@SuppressLint("ParcelCreator")来摆脱lint警告. (4认同)
  • 为什么这不再是数据类.这个例子只是为了表明这可以应用于任何通用的kotlin类吗? (3认同)
  • 对于那些想要查看它的人:https://blog.jetbrains.com/kotlin/2017/08/kotlin-1-1-4-is-out/ (2认同)

nek*_*ode 46

你可以尝试这个插件:

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)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


And*_*lix 29

一种更简单且最新的方法是使用注释@Parcelize,它消除了实现 Parcelable 的繁琐工作

build.gradle(应用程序模块)

apply plugin: "kotlin-parcelize"

// If you are using the new plugin format use this instead.
plugins{
    ...
    id "kotlin-parcelize"
}
Run Code Online (Sandbox Code Playgroud)

你的班级.kt

import kotlinx.parcelize

@Parcelize
class User(val firstName: String, val lastName: String, val age: Int): Parcelable
Run Code Online (Sandbox Code Playgroud)


Bra*_*ell 19

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

用法:

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

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

现在您的数据类是Parcelable并且可以直接传递给BundleIntent

编辑:使用最新API进行更新


Man*_*yal 16

只需单击您的kotlin数据类的data关键字,然后按alt + Enter,选择第一个选项说 "Add Parceable Implementation"

  • 我使用了这种方法,但它有几个问题。有时,如果字段不是 `val/var`,它会用 `TODO` 替换 `parcel.read...`。如果你在一个类中使用 `List`,你的实现就会成为一个问题。所以我在接受的答案中转向了`@Parcelize`。 (3认同)

Ste*_*ngo 15

没有样板代码的最好方法是Smuggler gradle插件.您只需要实现AutoParcelable接口即可

data class Person(val name:String, val age:Int): AutoParcelable
Run Code Online (Sandbox Code Playgroud)

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

UPD 17.08.2017现在有了Kotlin 1.1.4和Kotlin Android扩展插件,你可以使用@Parcelize注释.在这种情况下,上面的示例将如下所示:

@Parcelize class Person(val name:String, val age:Int): Parcelable
Run Code Online (Sandbox Code Playgroud)

不需要data修饰符.目前最大的缺点是使用kotlin-android-extensions插件,它有许多其他功能,可能是不必要的.


小智 12

  • 在模型/数据类之上使用@Parcelize注释
  • 使用最新版本的 Kotlin
  • 在您的应用模块中使用最新版本的 Kotlin Android 扩展

例子 :

@Parcelize
data class Item(
    var imageUrl: String,
    var title: String,
    var description: Category
) : Parcelable
Run Code Online (Sandbox Code Playgroud)


gme*_*rio 5

我会留下我的做法,以防它对某人有帮助。

我所做的是我有一个通用的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) }
Run Code Online (Sandbox Code Playgroud)

然后我创建这样的 Parcelables:

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()) } }
}
Run Code Online (Sandbox Code Playgroud)

这让我摆脱了样板覆盖。


arg*_*iwi 5

使用Android StudioKotlin插件,我发现了一种无需额外插件即可转换旧Java Parcelable的简便方法(如果您只想将全新的类转换为,请跳至第4个代码段)。 dataParcelable

假设您有一门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;
    }
}
Run Code Online (Sandbox Code Playgroud)

首先剥离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;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后让该Code > Convert Java file to Kotlin File选项发挥作用:

class Person(val firstName: String, val lastName: String, val age: Int)
Run Code Online (Sandbox Code Playgroud)

将此转换为data类:

data class Person(val firstName: String, val lastName: String, val age: Int)
Run Code Online (Sandbox Code Playgroud)

最后,让我们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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,Parcelable实现是将一些自动生成的代码附加到您的data类定义中。

笔记:

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

我希望这个技巧对您同样有用。


Mal*_*ngh 5

您可以使用@Parcelize注释来完成。它是一个自动 Parcelable 实现生成器。

首先,您需要启用它们,将其添加到您的模块的 build.gradle 中:

apply plugin: 'org.jetbrains.kotlin.android.extensions'
Run Code Online (Sandbox Code Playgroud)

在主构造函数中声明序列化属性并添加@Parcelize注释,writeToParcel()/createFromParcel()方法将自动创建:

@Parcelize
class User(val firstName: String, val lastName: String) : Parcelable
Run Code Online (Sandbox Code Playgroud)

DONT需要添加experimental = true内部androidExtensions块。