How to use Parcel.readTypedList() along with @Parc

2019-02-25 21:11发布

问题:

I'm running into a problem with implementing Parcelable-based state persistence in a View. Namely, as I need to implement the methods of BaseSavedState like this:

class SavedState : BaseSavedState {
    lateinit var myList: ArrayList<MyParcelable>

    constructor(superState: Parcelable) : super(superState) {}

    private constructor(parcel: Parcel) : super(parcel) {
        val listSize = parcel.readInt()
        val list = ArrayList<MyParcelable>(listSize)
        this.myList = parcel.readTypedList(list, /* needs MyParcelable.CREATOR */ )
    }

    override fun writeToParcel(out: Parcel, flags: Int) {
        super.writeToParcel(out, flags)
        out.writeInt(myList.size())
        out.writeTypedList(myList)
    }

    companion object {
        @JvmField
        val CREATOR: Parcelable.Creator<SavedState> = object : Parcelable.Creator<SavedState> {
            override fun createFromParcel(`in`: Parcel): SavedState {
                return SavedState(`in`)
            }

            override fun newArray(size: Int): Array<SavedState?> {
                return arrayOfNulls(size)
            }
        }
    }
}

However, as you can see, I can't seem to use Parcel.readTypedList() because it needs both the typed list, and the parcelable's CREATOR field!

Classes marked like:

@Parcelize
data class MyParcelable(val someData: String): Parcelable {
}

Do not have CREATORs, in fact, if you try to implement, it says:

'CREATOR' definition is not allowed. Use 'Parceler' companion object instead.

I do not want a Parceler companion object, I need a CREATOR!

I also kinda don't want to write the Parcelable implementation by hand, so I might just make it Serializable and be like "whatever".


Does anyone know by chance how you can use Parcel.readTypedList() with @Parcelize-annotated Kotlin data class?

回答1:

It's a bug on the Parcelize plugin like you mentioned https://youtrack.jetbrains.com/issue/KT-19853 and it can be solved by either reflection or actually, you can have a proxy class to java as you can access that CREATOR field in java without any problems.

I made a util java class for all creators and then made a kotlin extension referring to that creator

Java

@NonNull
public static Parcelable.Creator<Blah> getBlahCreator() {
    return Blah.CREATOR;
}

Kotlin

val Blah.Companion.CREATOR: Parcelable.Creator<Blah>
 get() = UtilClass.getBlahCreator()

And now I can access Blah.CREATOR anywhere! And those two classes that have all the creators and extensions could be just deleted later after the bug got fixed in the foreseeable future and it'll just work as expected without any edits in the other classes that use the CREATOR

This feels much better to me than the reflection solution! but either way, they are both disgusting and I hope this bug could be fixed soon enough!