Kotlin ile Android'de Parcelable veri sınıfları oluşturmanın uygun bir yolu var mı?


118

Şu anda Java projemde, Parcelable sınıflarının oluşturulmasını kolaylaştıran mükemmel AutoParcel kullanıyorum .

Şimdi, bir sonraki projem için düşündüğüm Kotlin, equals, hashCode ve toString yöntemlerini otomatik olarak üreten bu veri sınıfları kavramına sahip.

Bir Kotlin veri sınıfını uygun bir şekilde Parcelable yapmanın uygun bir yolu var mı (yöntemleri manuel olarak uygulamadan)?



AutoParcel'i Kotlin ile mi kullanmak istiyorsunuz? Bunu düşündüm, ancak Parcelable veri sınıflarının dilde yerleşik hale getirilmesinin bir yolu olsaydı, çok güzel olurdu. Özellikle Kotlin kullanımının büyük bir kısmının Android uygulamalarından geleceği düşünüldüğünde.
thalesmello

Yanıtlar:


188

Kotlin 1.1.4 çıktı

Android Uzantıları eklentisi artık otomatik bir Parcelable uygulama oluşturucu içeriyor. Birincil kurucuda serileştirilmiş özellikleri bildirin ve bir @Parcelize ek açıklaması ekleyin; writeToParcel () / createFromParcel () yöntemleri otomatik olarak oluşturulacaktır:

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

Bu nedenle, bunu modülünüzün build.gradle'ına eklemelerini etkinleştirmeniz gerekir :

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

android {
    androidExtensions {
        experimental = true
    }
}


3
bu neden artık veri sınıfı değil. Bu örnek, herhangi bir jenerik kotlin sınıfına uygulanabileceğini göstermek için mi?
Nitin Jain

10
derleyici şikayet ediyor this calss implements Parcelable but does not provice CREATOR field. Cevabınız yeterli mi (dolu)?
murt

1
@murt Parcelable'ı başarıyla kullandınız mı? CREATOR nedeniyle derleme hatasıyla karşılaşıyorum
TOP

4
@SuppressLint("ParcelCreator")Tüy bırakma uyarısından kurtulmak için kullanabilirsiniz .
Dutch Masters

47

Bu eklentiyi deneyebilirsiniz:

android-parcelable-intellij-eklenti-KOTLIN

Kotlin'in veri sınıfı için Android Parcelable standart kod oluşturmanıza yardımcı olur. Ve nihayet şöyle görünüyor:

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

20

Kotlin veri sınıfınızın veri anahtar kelimesini tıklayın, ardından alt + Enter tuşlarına basın, ilk seçeneği seçin "Add Parceable Implementation"


2
Bu yöntemi kullandım, ancak birkaç sorunu var. Bazen bir alan değilse, a parcel.read...ile yer değiştirir . Bir sınıf içinde kullanırsanız , uygulamanız bir sorun haline gelir. Ben de kabul edilen cevaba döndüm . TODOval/varList@Parcelize
CoolMind

19

PaperParcel'i denediniz mi? Bu Parcelable, sizin için Android standart kodunu otomatik olarak oluşturan bir açıklama işlemcisidir .

Kullanımı:

Veri sınıfınıza , oluşturulan örneğin bir JVM statik örneğini @PaperParceluygulayın PaperParcelable, uygulayın ve ekleyin.CREATOR

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

Artık veri sınıfınız Parcelabledoğrudan bir BundleveyaIntent

Düzenleme: En son API ile güncelleyin


IDE artık "Diğer sınıflardan veri sınıfı kalıtımının yasak olduğunu" söylüyor. PaperParcel'in artık veri sınıflarıyla kullanılamayacağını düşünüyorum ...
Massimo

Asla diğer sınıflardan miras alamazlar, ancak arayüzler uygulayabilirler (örneğin PaperParcelable)
Bradley Campbell

1
@Bradley Campbell Bu PaperParcelExample sınıf oluşturmak edemez bana bu hat JvmField val CREATOR = PaperParcelExample.CREATOR bir hata verir
Mr.G

16

Standart kod içermeyen en iyi yol Smuggler gradle eklentisidir. İhtiyacınız olan tek şey, AutoParcelable arayüzünü uygulamaktır.

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

Ve hepsi bu. Mühürlü sınıflar için de çalışıyor. Ayrıca bu eklenti, tüm AutoParcelable sınıfları için derleme zamanı doğrulaması sağlar.

GÜNCELLEME 17.08.2017 Artık Kotlin 1.1.4 ve Kotlin Android uzantıları eklentisi ile@Parcelize açıklama kullanabilirsiniz . Bu durumda yukarıdaki örnek şöyle görünecektir:

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

dataDeğiştiriciye gerek yok . Şimdilik en büyük dezavantajı, gereksiz olabilecek diğer birçok işleve sahip kotlin-android-uzantı eklentisi kullanmaktır.


6

Kullanımı Android Studio ve Kotlin eklentisi, benim eski Java dönüştürmek için kolay bir yol buldum Parcelableler ile hiçbir ekstra eklentileri (tüm istediğiniz yepyeni açmak için ise databir halinde sınıfı Parcelable, 4 kod parçalarında atlayın).

Diyelim ki Persontüm Parcelablekazan plakası olan bir sınıfınız var :

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

ParcelableUygulamayı çıkararak başlayın , çıplak kemikler, düz, eski bir Java nesnesi bırakın (özellikler nihai olmalı ve kurucu tarafından ayarlanmalıdır):

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

O zaman Code > Convert Java file to Kotlin Fileseçeneğin sihrini yapmasına izin verin :

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

Bunu bir datasınıfa dönüştürün :

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

Ve son olarak, bunu Parcelabletekrar a çevirelim. Sınıf adının üzerine gelin ve Android Studio size seçeneği sunmalıdır Add Parcelable Implementation. Sonuç şöyle görünmeli:

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

Gördüğünüz gibi, Parcelableuygulama, datasınıf tanımınıza eklenen otomatik olarak oluşturulmuş bir koddur .

Notlar:

  1. Bir Java'yı Parcelable doğrudan Kotlin'e dönüştürmeye çalışmak , Kotlin eklentisinin ( 1.1.3) mevcut sürümüyle aynı sonucu vermeyecektir .
  2. Mevcut Parcelablekod oluşturucunun sunduğu bazı fazladan kaşlı ayraçları kaldırmak zorunda kaldım . Küçük bir hata olmalı.

Umarım bu ipucu benim için olduğu kadar sizin için de işe yarar.


5
  • Model / Veri sınıfınızın üstünde @Parcelize ek açıklamasını kullanın
  • Kotlin'in en son sürümünü kullanın
  • Uygulama modülünüzde Kotlin Android Uzantılarının en son sürümünü kullanın

Misal :

@Parcelize
data class Item(
    var imageUrl: String,
    var title: String,
    var description: Category
) : Parcelable

4

Birine yardımcı olma ihtimaline karşı kendi yolumdan ayrılacağım.

Yaptığım şey bir jenerik var 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) }

Ve sonra bunun gibi parseller oluşturuyorum:

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

Bu da beni o standart geçersiz kılmadan kurtardı.


3

Ne yazık ki Kotlin'de bir arayüze gerçek bir alan koymanın bir yolu yoktur, bu nedenle onu bir arayüz adaptöründen ücretsiz olarak devralamazsınız: data class Par : MyParcelable

Yetkilendirmeye bakabilirsiniz, ancak alanlara yardımcı olmuyor, AFAIK: https://kotlinlang.org/docs/reference/delegation.html

Yani gördüğüm tek seçenek bir kumaş işlevi Parcelable.Creator, ki bu çok açık.



2

@ParcelizeEk açıklama kullanarak bunu yapabilirsiniz . Otomatik Parcelable uygulama üretecidir.

Öncelikle, bunu modülünüzün build.gradle'ına ekleyerek etkinleştirmeniz gerekir:

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

Birincil bir kurucuda serileştirilmiş özellikleri bildirin ve bir @Parcelizeaçıklama ekleyin ve writeToParcel()/ createFromParcel()yöntemler otomatik olarak oluşturulacaktır:

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

Sen dont ihtiyaç eklemek için experimental = trueandroidExtensionsbloğu.


1

Kotlin, @Parcel ek açıklaması ile Android'de tüm Parselizasyon sürecini çok kolaylaştırdı.

Bunu yapmak için

1. Adım Uygulama modülü notunuza Kotlin uzantıları ekleyin

Adım 2. Bu özellik hala aşamalı olarak deneme aşamasında olduğundan deneysel = true ekleyin.

androidExtensions {experimental = true}

Adım 3. Veri sınıfına @Parcel ile açıklama ekleyin

İşte @Parcel kullanımıyla ilgili basit bir örnek


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.