developer tip

Kotlin을 사용하여 Android에서 Parcelable 데이터 클래스를 만드는 편리한 방법이 있나요?

copycodes 2020. 8. 17. 09:12
반응형

Kotlin을 사용하여 Android에서 Parcelable 데이터 클래스를 만드는 편리한 방법이 있나요?


현재 Java 프로젝트에서 Parcelable 클래스 생성을 용이하게하는 뛰어난 AutoParcel사용하고 있습니다.

이제 다음 프로젝트에서 고려할 Kotlin에는 equals, hashCode 및 toString 메소드를 자동으로 생성하는 데이터 클래스 개념이 있습니다.

메서드를 수동으로 구현하지 않고 편리한 방식으로 Parcelable 데이터 클래스를 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'

android {
    androidExtensions {
        experimental = true
    }
}

이 플러그인을 사용해 볼 수 있습니다.

android-parcelable-intellij-plugin-kotlin

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상용구 코드를 자동으로 생성하는 주석 프로세서입니다 .

용법:

생성 된 JVM 정적 인스턴스를 사용 하여 데이터 클래스에 주석을 달고 @PaperParcel구현 PaperParcelable하고 추가합니다 CREATOR. 예 :

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

이제 데이터 클래스는 Parcelable과에 직접 전달할 수있는 BundleIntent

편집 : 최신 API로 업데이트


kotlin 데이터 클래스의 데이터 키워드를 클릭 한 다음 alt + Enter를 누르고 첫 번째 옵션을 선택하십시오. "Add Parceable Implementation"


최고의 와 방법은 없는 상용구 전혀 코드는 밀수의 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()) } }
}

Which gets me rid of that boilerplate override.


Using Android Studio and the Kotlin plugin, I found an easy way to convert my old Java Parcelables with no extra plugins (if all you want is to turn a brand new data class into a Parcelable, skip to the 4th code snippet).

Let's say you have a Person class with all the Parcelable boiler plate:

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

Start by stripping out the Parcelable implementation, leaving a bare-bones, plain, old Java object (properties should be final and set by the constructor):

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

Then let the Code > Convert Java file to Kotlin File option do its magic:

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

Convert this into a data class:

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

And finally, let's turn this into a Parcelable again. Hover the class name and Android Studio should give you the option to Add Parcelable Implementation. The result should look like this:

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

As you can see, the Parcelable implementation is some auto-generated code appended to you data class definition.

Notes:

  1. Trying to convert a Java Parcelable directly into Kotlin will not produce the same result with the current version of the Kotlin plugin (1.1.3).
  2. I had to remove some extra curly braces the current Parcelable code generator introduces. Must be a minor bug.

I hope this tip works for you as well as it did for me.


Unfortunately there is no way in Kotlin to put a real field in an interface, so you can't inherit it from an interface-adapter for free: data class Par : MyParcelable

You may look at delegation, but it does not help with fields, AFAIK: https://kotlinlang.org/docs/reference/delegation.html

So the the only option I see is a fabric function for Parcelable.Creator, which is kind of obvious.


i prefer just using the https://github.com/johncarl81/parceler lib with

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

  • Use @Parcelize annotation on top of your Model / Data class
  • Use latest version of Kotlin
  • Use latest version of Kotlin Android Extensions in your app module

Example :

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

There is a Plugin but is not always as updated as Kotlin is evolving: https://plugins.jetbrains.com/plugin/8086

Alternative: I have a working example of a custom data class using Parcelable and lists:

Data classes using Parcelable with Lists:

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

Hope it helps!


Kotlin has made the entire process of Parcelization in Android damn easy with its @Parcel annotation.

To do that

Step 1. Add Kotlin extensions in your app module gradle

Step 2. Add experimental = true since this feature is still in experimentation in gradle.

androidExtensions { experimental = true }

Step 3. Annonate the data class with @Parcel

Here is an simple example on @Parcel usage

참고URL : https://stackoverflow.com/questions/33551972/is-there-a-convenient-way-to-create-parcelable-data-classes-in-android-with-kotl

반응형