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

저는 현재 Parcelable 클래스 생성을 용이하게하는 Java 프로젝트에서 우수한 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)
            }
        }
    }
}


답변

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


답변

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로 업데이트


답변

최고의 와 방법은 없는 상용구 전혀 코드는 밀수의 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들과 별도의 플러그인 (당신이 원하는 모든 새로운 설정하는 경우 data로 클래스를 Parcelable, 제 4 코드로 건너을).

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클래스 정의에 추가 된 자동 생성 코드 입니다.

노트:

  1. 자바 ParcelableKotlin으로 직접 변환하려고 하면 현재 버전의 Kotlin 플러그인 ( 1.1.3) 과 동일한 결과가 생성되지 않습니다 .
  2. 현재 Parcelable코드 생성기에서 소개 하는 추가 중괄호를 제거해야했습니다 . 사소한 버그 여야합니다.

이 팁이 저와 마찬가지로 당신에게도 효과가 있기를 바랍니다.


답변

누군가에게 도움이 될 수있는 경우를 대비하여 내 방식을 떠날 것입니다.

내가하는 일은 일반 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()) } }
}

그러면 상용구 재정의가 제거됩니다.