Подтвердить что ты не робот

Есть ли удобный способ создания Parcelable классов данных в Android с Kotlin?

В настоящее время я использую отличный AutoParcel в своем проекте Java, что облегчает создание классов Parcelable.

Теперь, Kotlin, который я рассматриваю для моего следующего проекта, имеет эту концепцию классов данных, которые автоматически генерируют методы equals, hashCode и toString.

Есть ли удобный способ сделать класс данных Kotlin Parcelable удобным способом (без применения методов вручную)?

4b9b3361

Ответ 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, которая является очевидной.

Ответ 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