Есть ли удобный способ создания Parcelable классов данных в Android с Kotlin?
В настоящее время я использую отличный AutoParcel в своем проекте Java, что облегчает создание классов Parcelable.
Теперь, Kotlin, который я рассматриваю для моего следующего проекта, имеет эту концепцию классов данных, которые автоматически генерируют методы equals, hashCode и toString.
Есть ли удобный способ сделать класс данных Kotlin Parcelable удобным способом (без применения методов вручную)?
Ответы
Ответ 1
Kotlin 1.1.4 вышел
Плагин Android Extensions теперь включает в себя автоматический генератор реализации Parcelable. Объявите сериализованные свойства в первичном конструкторе и добавьте аннотацию @Parcelize, и методы writeToParcel()/createFromParcel() будут созданы автоматически:
@Parcelize
class User(val firstName: String, val lastName: String) : Parcelable
Поэтому вам нужно включить их, добавив в ваш модуль build.gradle:
apply plugin: 'org.jetbrains.kotlin.android.extensions'
android {
androidExtensions {
experimental = true
}
}
Ответ 2
Вы можете попробовать этот плагин:
android-parcelable-intellij-plugin-kotlin
Это поможет вам генерировать Android Parcelable шаблонный код для класса данных kotlin. И это, в конце концов, выглядит так:
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)
}
}
}
}
Ответ 3
Вы пробовали PaperParcel? Это обработчик аннотаций, который автоматически генерирует для вас шаблон шаблона Android Parcelable
.
Применение:
Аннотировать свой класс данных с помощью @PaperParcel
, реализовать PaperParcelable
и добавить статический экземпляр JVM сгенерированного CREATOR
например.
@PaperParcel
data class Example(
val test: Int,
...
) : PaperParcelable {
companion object {
@JvmField val CREATOR = PaperParcelExample.CREATOR
}
}
Теперь ваш класс данных Parcelable
и может быть передан непосредственно в Bundle
или Intent
Изменить: Обновление с помощью новейшего API
Ответ 4
Лучший способ без всякого шаблонного кода - плагин Smuggler 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, который имеет множество других функций, которые могут быть ненужными.
Ответ 5
Просто нажмите на ключевое слово data вашего класса данных kotlin, затем нажмите alt + Enter, выберите первый вариант с надписью "Add Parceable Implementation"
Ответ 6
Я оставлю свой способ сделать, если он может помочь кому-то.
Что я делаю, у меня есть общий 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()) } }
}
Который избавляет меня от переопределения шаблона.
Ответ 7
Используя Android Studio и плагин Kotlin, я нашел простой способ конвертировать мою старую 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 (свойства должны быть окончательными и заданы конструктором):
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
. Наведите имя класса, и 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
.
Примечания:
- Попытка конвертировать Java
Parcelable
непосредственно в Kotlin не приведет к такому же результату с текущей версией плагина Kotlin (1.1.3
).
- Мне пришлось удалить некоторые дополнительные фигурные скобки, которые вводит текущий генератор кода
Parcelable
. Должна быть небольшая ошибка.
Я надеюсь, что этот совет будет работать для вас, а также для меня.
Ответ 8
К сожалению, в Kotlin нет способа разместить реальное поле в интерфейсе, поэтому вы не можете наследовать его от интерфейса-адаптера бесплатно:
data class Par : MyParcelable
Вы можете посмотреть на делегирование, но это не помогает с полями, AFAIK: https://kotlinlang.org/docs/reference/delegation.html
Итак, единственная опция, которую я вижу, - это теневая функция для Parcelable.Creator
, которая является очевидной.
Ответ 9
Я предпочитаю использовать https://github.com/johncarl81/parceler lib с
@Parcel(Parcel.Serialization.BEAN)
data class MyClass(val value)
Ответ 10
Существует плагин, но он не всегда обновляется по мере развития Kotlin:
https://plugins.jetbrains.com/plugin/8086
Альтернатива:
У меня есть рабочий пример пользовательского класса данных с помощью Parcelable
и списки:
Классы данных с использованием Parcelable со списками:
https://gist.github.com/juanchosaravia/0b61204551d4ec815bbf
Надеюсь, что это поможет!
Ответ 11
Благодаря аннотации @Parcel, Kotlin упростил весь процесс Parcelization в Android.
Для этого
Шаг 1. Добавьте расширения Kotlin в свой модуль модуля gradle
Шаг 2. Добавьте экспериментальный = true, так как эта функция все еще находится в экспериментах в Gradle.
androidExtensions {экспериментальный = правда}
Шаг 3. Аннонировать класс данных с помощью @Parcel
Вот простой пример использования @Parcel
Ответ 12
- Используйте аннотацию @Parcelize поверх вашего класса Model/Data
- Используйте последнюю версию Kotlin
- Используйте последнюю версию Kotlin Android Extensions в вашем модуле приложения
Пример:
@Parcelize
data class Item(
var imageUrl: String,
var title: String,
var description: Category
) : Parcelable